Scala 的類型推斷
按照官方的說法,Scala 的類型推斷是基于流(flow based)的,假設有方法如下:
foldRight[A, B](xs: List[A], z: B)(f: (A, B) => B): B = {
case Nil => z
case h :: t => f(t, foldRight(t, z)(f))
}
這個方法的類型是經過柯里化的、多態(tài)的方法類型,它接收兩組參數列表,一組為普通入參,另一組為函數入參
方法 foldRight[A, B](xs: List[A], z: B])(f: (A, B) => B): B 中的 [A, B] 就是該方法的類型參數。從類型推斷算法執(zhí)行的過程分析,foldRight 需要先用類型參數實例化(所謂類型實例)以后才能被應用到它的入參上,需要先指定 [A, B] 中 A 和 B 的類型
何為類型參數實例化
按照如下調用的方式,可以理解方法的類型參數實例化
// 比如求一個 List[String] 類型列表的長度
val length = foldRight[String, Int](List("a", "b", "c"), 0)((_, Int: len) => 1 + len)
上面的寫法就是先通過 foldRight[String, Int] 指定 foldRight[A, B] 的參數類型為 String 和 Int 來將方法進行類型參數實例化,這樣后面的兩個參數列表就可以應用指定的類型參數進行類型推斷,所以第二個參數列表就可以使用 _ 進行簡寫
普遍調用方式
上述的調用方式,會顯得過于累贅,而且也不能更為精簡的使用泛化函數,普通的調用會是這樣
val sum = foldRight(List(1, 2, 3, 4), 0)(_ + _)
對于這種情況,foldRight 沒有給出確切的類型參數實例,類型推斷算法會改變策略,會先檢查首個參數列表的所有入參類型,并應用到方法的類型參數實例,后續(xù)的參數列表就可以使用方法的類型參數信息了。就是先通過(List(1, 2, 3, 4), 0) 推斷出 foldRight[Int, Int],后續(xù)的 (_ + _) 就可以推斷為 (x: Int, y: Int) => x + y 其中x、y是隨便命名的
具體的過程如下所示:

類型推斷算法總結
當類型推斷算法需要推斷一個多態(tài)方法的類型參數時,他會考慮第一個參數列表的所有入參類型,到此為止。第二個入參列表并不會用來判定方法的類型參數
類庫函數的設計原則
當設計一個接收某些非函數的入參和一個函數入參時,將函數入參單獨放在最后一個參數列表中。這樣,方法的實例類型可以從那些非函數入參推斷出來,而這些類型又能被繼續(xù)用于對函數入參做類型檢查。這樣方法的使用者需要給出的類型信息更少,因而在編寫函數字面量時可以更精簡
其他情況
因為類型算法只會使用第一個參數列表作為方法實例類型的依據,所以在有些局部的情況下,通過顯式添加類型注解來解決問題