2015-04-27 12 views
5

Tôi đang đọc Lập trình chức năng ở Scala và trong chương 04, các tác giả thực hiện Tùy chọn theo cách riêng của họ. Bây giờ, khi xác định các chức năng getOrElse họ sử dụng một trên ràng buộc để hạn chế các loại A đến một supertype (nếu hiểu một cách chính xác)Scala Kiểu tùy chọn giới hạn trên không hiểu

Vì vậy, định nghĩa đi:

sealed trait Option[+A] { 
    def getOrElse[B >: A](default: => B): B = this match { 
    case None => default 
    case Some(a) => a 
    } 
} 

Vì vậy, khi chúng ta có một cái gì đó như

val a = Some(4) 
println(a.getOrElse(None)) => println prints a integer value 
val b = None 
println(b.getOrElse(Some(3)) => println prints a Option[Integer] value 

a có kiểu Option[Int], vì vậy A sẽ loại Int. B sẽ là loại Nothing. Nothing là loại phụ của mọi loại khác. Điều đó có nghĩa là Option[Nothing] là một loại phụ của Option[Int] (do hiệp phương sai), phải không?

Nhưng với B >: A chúng tôi đã nói rằng B phải là một siêu kiểu ?! Vậy làm thế nào chúng ta có thể lấy lại một số Int? Điều này hơi khó hiểu đối với tôi ...

Bất kỳ ai quan tâm để thử và làm rõ?

Trả lời

8

Điều đó có nghĩa là Tùy chọn [Không có gì] là loại phụ của Tùy chọn [Int] (do hiệp phương sai), phải không?

Đúng. Option[Nothing]Option[Int].

Nhưng với B>: A chúng tôi đã nói rằng B phải là siêu nhân ?! Vậy làm thế nào chúng ta có thể lấy lại Int?

Nó không phải là siêu kiểu. Nó chỉ yêu cầu A dưới dạng giới hạn dưới. Điều này có nghĩa là bạn vẫn có thể vượt qua Int đến getOrElse nếu AInt.

Nhưng điều đó không có nghĩa là bạn không thể chuyển trường hợp của một lớp con. Ví dụ:

class A 
class B extends A 
class C extends B 

scala> Option(new B) 
res196: Option[B] = Some([email protected]) 

scala> res196.getOrElse(new C) 
res197: B = [email protected] 

scala> res196.getOrElse(new A) 
res198: A = [email protected] 

scala> res196.getOrElse("...") 
res199: Object = [email protected] 

tôi vẫn có thể vượt qua một thể hiện của C, vì C có thể lên-cast để B. Tôi cũng có thể vượt qua một loại cao hơn cây thừa kế, và thay vào đó, getOrElse sẽ trả về loại đó. Nếu tôi chuyển loại không liên quan đến loại có trong số Option, thì loại có giới hạn trên ít nhất sẽ được suy ra. Trong trường hợp trên, nó là Any.


Vậy tại sao có giới hạn thấp hơn? Tại sao không có:

def getOrElse[B <: A](default: => B): B 

này sẽ không làm việc vì getOrElse phải hoặc trả lại A đó là chứa trong Option, hoặc mặc định B. Nhưng nếu chúng tôi trả lại AA không phải là B, do đó, loại giới hạn không hợp lệ.Có lẽ nếu getOrElse trở A:

def getOrElse[B <: A](default: => B): A 

này sẽ làm việc (nếu nó đã thực sự được xác định như vậy), nhưng bạn sẽ bị hạn chế bởi các loại-giới hạn. Vì vậy, trong ví dụ trên, bạn chỉ có thể vượt qua B hoặc C đến getOrElse trên Option[B]. Trong mọi trường hợp, đây không phải là cách nó nằm trong thư viện chuẩn.


Thư viện chuẩn getOrElse cho phép bạn chuyển bất kỳ thứ gì cho nó. Giả sử bạn có Option[A]. Nếu chúng tôi chuyển loại phụ của A, thì nó sẽ được truyền lên A. Nếu chúng tôi vượt qua A, rõ ràng điều này là không sao. Và nếu chúng ta vượt qua một số loại khác, thì trình biên dịch sẽ thâm nhập giới hạn trên ít nhất giữa hai loại. Trong mọi trường hợp, đáp ứng B >: A loại được ràng buộc.

getOrElse cho phép bạn chuyển bất kỳ thứ gì cho nó, nhiều người coi nó rất phức tạp. Ví dụ: bạn có thể có:

val number = "blah" 
// ... lots of code 
val result = Option(1).getOrElse(number) 

Và điều này sẽ biên dịch. Chúng tôi sẽ chỉ có một số Option[Any] có thể sẽ gây ra lỗi ở một nơi khác trên đường truyền.

+0

Cảm ơn bạn, nhưng bạn có thể vui lòng cung cấp ví dụ về loại chúng tôi không thể chuyển sang res196.getOrElse ... hiện tại, với ví dụ này, tôi không thấy điểm có giới hạn thấp hơn. Hoặc tốt hơn để nói, bây giờ tôi không hiểu ý nghĩa của một loại là giới hạn thấp hơn ... – Marin

+0

@Marin Bạn có thể chuyển bất kỳ loại nào thành 'getOrElse'. Xem chỉnh sửa của tôi. –

+0

cảm ơn! Tôi nghĩ rằng tôi nhận được nó ngay bây giờ. – Marin

Các vấn đề liên quan