Bản kê khai trong Scala là gì và khi nào bạn cần nó?


132

Vì Scala 2.7.2, có một cái gì đó gọi Manifestlà giải pháp thay thế cho kiểu xóa Java. Nhưng làm thế nào để Manifesthoạt động chính xác và tại sao / khi nào bạn cần sử dụng nó?

Bài đăng trên blog Bản kê khai: Các loại hợp nhất của Jorge Ortiz giải thích một số phần, nhưng nó không giải thích cách sử dụng nó cùng với giới hạn ngữ cảnh .

Ngoài ra, ClassManifestsự khác biệt là Manifestgì?

Tôi có một số mã (một phần của chương trình lớn hơn, không thể dễ dàng đưa nó vào đây) có một số cảnh báo liên quan đến việc xóa kiểu; Tôi nghi ngờ tôi có thể giải quyết những điều này bằng cách sử dụng bảng kê khai, nhưng tôi không chắc chính xác bằng cách nào.


2
Đã có một cuộc thảo luận về danh sách gửi thư về sự khác biệt của Manifest / ClassManifest, xem scala-programming-lingu.1934581.n4.nabble.com/
Arjan Blokzijl

Câu trả lời:


197

Trình biên dịch biết nhiều thông tin về các kiểu hơn thời gian chạy JVM có thể dễ dàng biểu diễn. Bản kê khai là cách để trình biên dịch gửi thông điệp liên chiều tới mã trong thời gian chạy về thông tin loại đã bị mất.

Điều này tương tự như cách người Klepton đã để lại những thông điệp được mã hóa trong hồ sơ hóa thạch và DNA "rác" của con người. Do những hạn chế của trường cộng hưởng ánh sáng và lực hấp dẫn, chúng không thể giao tiếp trực tiếp. Nhưng, nếu bạn biết cách điều chỉnh tín hiệu của họ, bạn có thể hưởng lợi theo những cách mà bạn không thể tưởng tượng được, từ việc quyết định ăn gì cho bữa trưa hoặc số lotto nào để chơi.

Không rõ liệu Bản kê khai có lợi cho những lỗi bạn đang gặp mà không biết thêm chi tiết hay không.

Một cách sử dụng phổ biến của Biểu hiện là để mã của bạn hoạt động khác nhau dựa trên loại tĩnh của bộ sưu tập. Ví dụ: nếu bạn muốn đối xử với Danh sách [Chuỗi] khác với các loại Danh sách khác:

 def foo[T](x: List[T])(implicit m: Manifest[T]) = {
    if (m <:< manifest[String])
      println("Hey, this list is full of strings")
    else
      println("Non-stringy list")
  }

  foo(List("one", "two")) // Hey, this list is full of strings
  foo(List(1, 2)) // Non-stringy list
  foo(List("one", 2)) // Non-stringy list

Một giải pháp dựa trên phản ánh cho điều này có thể sẽ liên quan đến việc kiểm tra từng yếu tố của danh sách.

Một bối cảnh bị ràng buộc có vẻ phù hợp nhất với việc sử dụng các loại lớp trong scala và được giải thích rõ ở đây bởi Debasish Ghosh: http://debasishg.blogspot.com/2010/06/scala-implicits-type-classes-here-i.html

Giới hạn bối cảnh cũng có thể làm cho chữ ký phương thức dễ đọc hơn. Ví dụ, hàm trên có thể được viết lại bằng cách sử dụng giới hạn ngữ cảnh như vậy:

  def foo[T: Manifest](x: List[T]) = {
    if (manifest[T] <:< manifest[String])
      println("Hey, this list is full of strings")
    else
      println("Non-stringy list")
  }

25

Không phải là một câu trả lời hoàn chỉnh, nhưng liên quan đến sự khác biệt giữa ManifestClassManifest, bạn có thể tìm thấy một ví dụ trong bài báo Scala 2.8Array :

Câu hỏi duy nhất còn lại là làm thế nào để thực hiện tạo mảng chung. Không giống như Java, Scala cho phép tạo một cá thể mới Array[T]trong đó Tlà một tham số kiểu. Làm thế nào điều này có thể được thực hiện, với thực tế là không tồn tại một biểu diễn mảng thống nhất trong Java?

Cách duy nhất để làm điều này là yêu cầu thông tin thời gian chạy bổ sung mô tả loại T. Scala 2.8 có một cơ chế mới cho việc này, được gọi là Bản kê khai . Một đối tượng của loại Manifest[T]cung cấp thông tin đầy đủ về loại T.
Manifestcác giá trị thường được truyền trong các tham số ngầm; và trình biên dịch biết cách xây dựng chúng cho các kiểu được biết đến tĩnh T.

Ngoài ra còn tồn tại một dạng yếu hơn có tên ClassManifestcó thể được xây dựng từ việc chỉ biết lớp cấp cao nhất của một loại, mà không nhất thiết phải biết tất cả các loại đối số của nó .
Đây là loại thông tin thời gian chạy cần thiết cho việc tạo mảng.

Thí dụ:

Người ta cần cung cấp thông tin này bằng cách chuyển một ClassManifest[T]phương thức thành một tham số ngầm định:

def  tabulate[T](len:Int,  f:Int=>T)(implicit m:ClassManifest[T]) =  { 
  val  xs  =  new  Array[T](len) 
  for   (i  <- 0  until   len)  xs(i)   = f(i) 
  xs 
} 

Là một dạng tốc ký, một bối cảnh ràng buộc1 có thể được sử dụng trên tham số loại Tthay thế,

(Xem câu hỏi SO này để minh họa )

, cho:

def  tabulate[T:    ClassManifest](len:Int,  f:Int=>T)  =  { 
  val  xs  =  new  Array[T](len) 
  for   (i  <- 0  until   len)  xs(i)   = f(i) 
  xs 
} 

Khi gọi lập bảng trên một kiểu như Int, hoặc String, hoặc List[T], trình biên dịch Scala có thể tạo một bảng kê khai lớp để chuyển dưới dạng đối số ngầm để lập bảng.


25

Một Manifest được dự định để thống nhất các loại chung bị xóa loại để chạy trên JVM (không hỗ trợ chung chung). Tuy nhiên, họ có một số vấn đề nghiêm trọng: chúng quá đơn giản và không thể hỗ trợ đầy đủ hệ thống loại của Scala. Do đó, chúng không được dùng trong Scala 2.10 và được thay thế bằng TypeTags (về cơ bản là những gì trình biên dịch Scala sử dụng để biểu diễn các loại và do đó hỗ trợ đầy đủ các loại Scala). Để biết thêm chi tiết về sự khác biệt, xem:

Nói cách khác

Khi nào bạn cần nó?

Trước 2013-01-04, khi Scala 2.10 được phát hành .


Nó chưa được phản đối (nhưng sẽ được), vì sự phản chiếu của Scala vẫn đang thử nghiệm trong 2.10.
Keros

Trước 2013-01-04 hoặc nếu bạn đang sử dụng API dựa trên API.
David Moles

1

Chúng ta cũng tìm hiểu manifestvề scalacác nguồn ( Manifest.scala), chúng ta thấy:

Manifest.scala:
def manifest[T](implicit m: Manifest[T])           = m

Vì vậy, liên quan đến mã ví dụ sau:

def foo[A](somelist: List[A])(implicit m: Manifest[A]): String = {
  if (m <:< manifest[String]) {
    "its a string"
  } else {
    "its not a string"
  }
}

chúng ta có thể thấy rằng các manifest functiontìm kiếm cho một ẩn m: Manifest[T]ý thỏa mãn những type parametergì bạn cung cấp trong mã ví dụ của chúng tôi manifest[String]. Vì vậy, khi bạn gọi một cái gì đó như:

if (m <:< manifest[String]) {

bạn đang kiểm tra xem dòng điện implicit mmà bạn xác định trong hàm của bạn có thuộc loại không manifest[String]và vì đây manifestlà chức năng của loại manifest[T]nó sẽ tìm kiếm cụ thể manifest[String]và nó sẽ tìm xem có ẩn ý như vậy không.

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.