3 回答

TA貢獻1829條經驗 獲得超6個贊
我同意推斷“唯一可能的”類型會很好,即使調用是鏈接在一起的,但存在技術限制。
您可以將推理視為對表達式的廣度優先掃描,收集對類型變量的約束(由子類型邊界和必需的隱式參數引起),然后求解這些約束。這種方法允許例如隱式指導類型推斷。在您的示例中,即使僅查看xs.toSet
子表達式也有一個解決方案,但是以后的鏈接調用可能會引入使系統無法滿足的約束。保留類型變量未解決的缺點是,對閉包的類型推斷需要知道目標類型,因此將失敗(它需要做一些具體的事情-所需的閉包類型及其參數類型必須并非兩者都是未知的)。
現在,當延遲解決約束使推理失敗時,我們可以回溯,解決所有類型變量,然后重試,但是實現起來很棘手(可能效率很低)。

TA貢獻1871條經驗 獲得超8個贊
類型推斷無法正常工作,因為List#toSetis 的簽名
def toSet[B >: A] => scala.collection.immutable.Set[B]
并且編譯器需要在調用中的兩個位置推斷類型。在函數中注釋參數的另一種方法是toSet使用顯式類型參數進行調用:
xs.toSet[Int] map (_*2)
更新:
關于您的問題,為什么編譯器可以分兩步進行推斷,讓我們看一下一一行地輸入行時會發生什么:
scala> val xs = List(1,2,3)
xs: List[Int] = List(1, 2, 3)
scala> val ys = xs.toSet
ys: scala.collection.immutable.Set[Int] = Set(1, 2, 3)
在這里,編譯器會推斷出最具體類型,ys這是Set[Int]在這種情況下?,F在已經知道這種類型,因此map可以推斷傳遞給函數的類型。
如果在示例中填寫了所有可能的類型參數,則調用將寫為:
xs.toSet[Int].map[Int,Set[Int]](_*2)
第二個type參數用于指定返回的集合的類型(有關詳細信息,請查看Scala集合的實現方式)。這意味著我什至低估了編譯器必須推斷的類型數量。
在這種情況下,似乎很容易推斷出來,Int但在某些情況下卻并非如此(鑒于Scala的其他功能,例如隱式轉換,單例類型,混合的特性等)。我并不是說這無法完成-只是Scala編譯器沒有做到這一點。
- 3 回答
- 0 關注
- 478 瀏覽
添加回答
舉報