Hiểu từ khóa 'gõ' trong Scala là gì


144

Tôi chưa quen với Scala và tôi thực sự không thể tìm thấy nhiều về typetừ khóa. Tôi đang cố gắng hiểu những gì biểu hiện sau đây có thể có nghĩa:

type FunctorType = (LocalDate, HolidayCalendar, Int, Boolean) => LocalDate

FunctorType là một loại bí danh, nhưng nó biểu thị điều gì?

Câu trả lời:


148

Có, bí danh loại FunctorType chỉ là một tốc ký cho

(LocalDate, HolidayCalendar, Int, Boolean) => LocalDate

Các bí danh loại thường được sử dụng để giữ cho phần còn lại của mã đơn giản: bây giờ bạn có thể viết

def doSomeThing(f: FunctorType)

mà trình biên dịch sẽ hiểu là

def doSomeThing(f: (LocalDate, HolidayCalendar, Int, Boolean) => LocalDate)

Điều này giúp tránh việc xác định nhiều loại tùy chỉnh chỉ là bộ dữ liệu hoặc hàm được xác định trên các loại khác, chẳng hạn.

Ngoài ra còn có một số trường hợp sử dụng thú vị khác cho type, như mô tả ví dụ trong chương này của lập trình trong Scala .


198

Trên thực tế, typetừ khóa trong Scala có thể làm được nhiều hơn là chỉ đặt bí danh cho một loại phức tạp thành một tên ngắn hơn. Nó giới thiệu các thành viên loại .

Như bạn đã biết, một lớp có thể có các thành viên trường và các thành viên phương thức. Chà, Scala cũng cho phép một lớp có thành viên loại.

Trong trường hợp cụ thể của bạn type, thực sự, giới thiệu một bí danh cho phép bạn viết mã ngắn gọn hơn. Hệ thống loại chỉ thay thế bí danh bằng loại thực tế khi kiểm tra loại được thực hiện.

Nhưng bạn cũng có thể có một cái gì đó như thế này

trait Base {
  type T

  def method: T
}

class Implementation extends Base {
  type T = Int

  def method: T = 42
}

Giống như bất kỳ thành viên nào khác của một lớp, các thành viên loại cũng có thể trừu tượng (bạn chỉ không xác định giá trị thực sự của chúng là gì) và có thể bị ghi đè trong các triển khai.

Các thành viên loại có thể được xem như là kép của tướng vì nhiều điều bạn có thể thực hiện với thuốc generic có thể được dịch thành các loại thành viên trừu tượng.

Vì vậy, có, chúng có thể được sử dụng để khử răng cưa, nhưng đừng giới hạn chúng chỉ vì điều này, vì chúng là một tính năng mạnh mẽ của hệ thống loại của Scala.

Xin vui lòng xem câu trả lời tuyệt vời này để biết thêm chi tiết:

Scala: Tóm tắt các loại vs tướng


44
Điều quan trọng cần nhớ là việc sử dụng kiểu bên trong một lớp sẽ tạo ra một thành viên kiểu thay vì bí danh. Vì vậy, nếu bạn chỉ cần một bí danh loại, hãy xác định nó trong đối tượng đồng hành.
Rüdiger Klaehn

9

Tôi thích câu trả lời từ Roland Ewald vì anh ấy đã mô tả với một trường hợp sử dụng bí danh rất đơn giản và để biết thêm chi tiết giới thiệu một hướng dẫn rất hay. Tuy nhiên, vì một trường hợp sử dụng khác được giới thiệu trong bài đăng có tên thành viên loại này , tôi muốn đề cập đến trường hợp sử dụng thực tế nhất của nó, điều mà tôi rất thích: (phần này được lấy từ đây :)

Loại trừu tượng:

type T

T ở trên nói rằng loại này sẽ được sử dụng, chưa được biết và tùy thuộc vào lớp con cụ thể, nó sẽ được xác định. Cách tốt nhất luôn để hiểu các khái niệm lập trình là cung cấp một ví dụ: Giả sử bạn có kịch bản sau:

Không có loại trừu tượng

Ở đây bạn sẽ gặp lỗi biên dịch, bởi vì phương thức eat trong các lớp Cow và Tiger không ghi đè phương thức eat trong lớp Animal, bởi vì các loại tham số của chúng là khác nhau. Đó là Cỏ trong lớp Bò và Thịt trong lớp Hổ so với Thức ăn trong lớp Động vật là siêu hạng và tất cả các lớp con phải tuân thủ.

Bây giờ quay lại kiểu trừu tượng, bằng sơ đồ sau và chỉ cần thêm một kiểu trừu tượng, bạn có thể định nghĩa kiểu đầu vào, theo chính lớp con.

Với loại trừu tượng

Bây giờ hãy xem các mã sau:

  val cow1: Cow = new Cow
  val cow2: Cow = new Cow

  cow1 eat new cow1.SuitableFood
  cow2 eat new cow1.SuitableFood

  val tiger: Tiger = new Tiger
  cow1 eat new tiger.SuitableFood // Compiler error

Trình biên dịch là hạnh phúc và chúng tôi cải thiện thiết kế của chúng tôi. Chúng ta có thể nuôi bò bằng bò. Phù hợp với thức ăn và trình biên dịch ngăn chúng ta cho bò ăn thức ăn phù hợp với Tiger. Nhưng điều gì sẽ xảy ra nếu chúng ta muốn tạo sự khác biệt giữa loại bò1 Thích hợp Thực phẩm và Bò2 SuitabeFood. Nói cách khác, nó sẽ rất tiện trong một số trường hợp nếu đường dẫn mà chúng ta tiếp cận với loại (tất nhiên thông qua đối tượng) về cơ bản không thành vấn đề. Nhờ các tính năng nâng cao trong scala, có thể:

Các loại phụ thuộc vào đường dẫn: Các đối tượng Scala có thể có các loại là thành viên. Ý nghĩa của loại, phụ thuộc vào đường dẫn bạn sử dụng để truy cập nó. Đường dẫn được xác định bởi tham chiếu đến một đối tượng (còn gọi là một thể hiện của một lớp). Để thực hiện kịch bản này, bạn cần xác định lớp Grass bên trong Cow, tức là Cow là lớp bên ngoài và Grass là lớp bên trong. Cấu trúc sẽ như thế này:

  class Cow extends Animal {
    class Grass extends Food
    type SuitableFood = Grass
    override def eat(food: this.SuitableFood): Unit = {}
  }

  class Tiger extends Animal {
    class Meat extends Food
    type SuitableFood = Meat
    override def eat(food: this.SuitableFood): Unit = {}
  }

Bây giờ nếu bạn cố gắng biên dịch mã này:

  1. val cow1: Cow = new Cow
  2. val cow2: Cow = new Cow

  3. cow1 eat new cow1.SuitableFood
  4. cow2 eat new cow1.SuitableFood // compilation error

Trên dòng 4 bạn sẽ thấy một lỗi vì Grass hiện là một lớp bên trong của Cow, do đó, để tạo một thể hiện của Grass, chúng ta cần một đối tượng bò và đối tượng bò này xác định đường dẫn. Vì vậy, 2 đối tượng bò cho ra 2 con đường khác nhau. Trong kịch bản này, cow2 chỉ muốn ăn thức ăn được tạo ra đặc biệt cho nó. Vì thế:

cow2 eat new cow2.SuitableFood

Bây giờ mọi người đều hạnh phúc :-)


5

Chỉ là một ví dụ để xem cách sử dụng "loại" làm bí danh:

type Action = () => Unit

Định nghĩa trên định nghĩa Hành động là bí danh của loại thủ tục (phương thức) có danh sách tham số trống và Đơn vị trả về đó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.