給定以下代碼
sealed trait Fruit
case class Apple(color: String) extends Fruit
case class Orange(color: String) extends Fruit
def getAppleColor(apple: Apple) = apple.color
def getOrangeColor(orange: Orange) = orange.color
val myMap: Map[String, Fruit] = Map(
"myApple" -> Apple("red"),
"myOrange" -> Orange("orange"),
)
val myMapOfFunctions: Map[String, Apple with Orange => String] = Map(
"myAppleColorFun" -> getAppleColor,
"myOrangeColorFun" -> getOrangeColor,
)
為什么myMapOfFunctions不是一個Map[String, Fruit => String]類似的myMap?我猜是因為它是關于功能的,但我想更好地理解為什么。謝謝!
uj5u.com熱心網友回復:
我只是想了解為什么編譯器說地圖的型別是 Apple with Orange 而不是 Fruit
好的,好在這很“容易”解釋。
不好的是,它可能不那么容易理解。
讓我們退后幾步,通過使用 anif而不是集合來稍微簡化代碼。
當你做這樣的事情時:
val foo = if (bar) x else y
編譯器必須推斷 的型別foo,為此它將首先獲取/推斷xand的型別y;讓我們分別呼叫這些X&Y然后計算兩者之間的 LUB (最小上限),從而產生一個新型別Z,該型別將是分配給的型別。foo
這是有道理的,因為X <: Z因此Y <: ZLiskov 受到尊重。
快速注意,如果
X和Y是相同的型別A,那么 LUB 只是A
另一個快速的,如果X是一個子型別,Y那么 LUB 就是Y
讓我們看看應用于簡單型別的那些:
val fruit = if (true) Apple(color = "red") else Orange(color = "green")
在這里,一個分支具有型別,另一個分支具有 ,Apple兩者Orange之間的 LUB 是Fruit。
到目前為止,一切都很簡單。
現在,讓我們稍微調劑一下:
val optApple: Option[Apple] = Apple(color = "red")
val optOrange: Option[Orange] = Orange(color = "green")
val optFruit = if (true) optApple else optOrange
這里一個分支是Option[Apple],另一個是Option[Orange],我們知道結果會是Option[Fruit],但是為什么呢?
好吧,因為Option被定義為在其型別引數上是協變的,因此Option[Fruit]是兩個分支的超型別;主要是LUB。
好的,但是函式會發生什么?
// Implementations do not matter.
val appleFunction : Apple => Apple = ???
val orangeFunction: Orange => Orange = ???
val fruitFunction = if (true) appleFunction else orangeFunction
在這種情況下,LUB 將是(Apple with Orange) => Fruit……但是為什么呢?
好吧,回傳很容易,因為函式的回傳也是協變的,這意味著 LUB 將再次是Fruit
但是,為什么輸入不是這樣呢?好吧,因為函式的輸入是逆變的,因此一個函式f要成為另一個函式的子g型別,輸入的型別f必須是輸入的超型別g;即它以相反的順序進行,這就是為什么它被稱為逆變。
這就解釋了為什么編譯器會推斷出這種型別。
但是,您可能想知道這種差異業務是什么,為什么它很重要,以及為什么有一個看起來違反直覺的業務。但這超出了本問答的范圍。
不過,我可以分享一些可能有用的資源:
- https://www.youtube.com/watch?v=aUmj7jnXet4&t=53s
- https://www.youtube.com/watch?v=b1ftkK1zhxI&t=3s
- 在函式引數 A => B 的逆變位置接受的協變型別 A
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/486218.html
