過載解析的變更
Scala 3 中的重載解析在三個方面優於 Scala 2。首先,它會考量所有引數清單,而不仅仅是第一個引數清單。其次,它可以推論函式值的參數類型,即使它們在第一個引數清單中。第三,預設引數不再與優先順序相關。
檢視第一個引數清單之外
在選擇一組重載替代方案時,重載解析現在可以考量引數清單。例如,下列程式碼會編譯在 Scala 3 中,而在 Scala 2 中會產生模稜兩可的重載錯誤
def f(x: Int)(y: String): Int = 0
def f(x: Int)(y: Int): Int = 0
f(3)("") // ok
下列程式碼也會編譯
def g(x: Int)(y: Int)(z: Int): Int = 0
def g(x: Int)(y: Int)(z: String): Int = 0
g(2)(3)(4) // ok
g(2)(3)("") // ok
為了讓此功能運作,SLS §6.26.3 中的重載解析規則會增強如下
在函式套用至多個引數清單的情況下,如果在考量
n >= 1
參數清單時,重載解析產生多個競爭的替代方案,則會使用n + 1
個引數清單重新嘗試解析。
此變更的動機是新的語言功能 擴充方法,其中出現了基於額外引數區塊進行重載解析的需求。
函數值的參數類型
改進了對缺少參數類型的函數值的處理。我們現在可以在重載應用程式的第一個引數清單中傳遞此類值,前提是其餘參數足以選擇重載函數的變體。例如,以下程式碼在 Scala 3 中編譯,而在 Scala2 中會導致缺少參數類型錯誤
def f(x: Int, f2: Int => Int) = f2(x)
def f(x: String, f2: String => String) = f2(x)
f("a", _.toUpperCase)
f(2, _ * 2)
為使此功能正常運作,SLS §6.26.3 中的重載解析規則已修改如下
替換句子
否則,讓
S1,...,Sm
成為透過使用未定義預期類型鍵入每個引數而取得的類型向量。
為以下段落
否則,讓
S1,...,Sm
成為所有引數類型的已知類型向量,其中引數E
的已知類型的判定方式如下
- 如果
E
是缺少一些參數類型的函數值(p_1, ..., p_n) => B
,則E
的已知類型為(S_1, ..., S_n) => ?
,其中每個S_i
為參數p_i
的類型(如果已提供),否則為?
。在此,?
代表與所有其他類型相容的萬用字元類型。 - 否則,
E
的已知類型為使用未定義預期類型鍵入E
的結果。
樣式比對封閉
{ case P1 => B1 ... case P_n => B_n }
被視為已擴充至函數值
x => x match { case P1 => B1 ... case P_n => B_n }
因此也近似為 ? => ?
類型。
預設引數不再與優先順序相關
在 Scala 2 中,如果在幾個應用程式替代方案中有一個替代方案具有預設引數,則該替代方案會從考量中刪除。這會產生一個不幸的副作用,即為方法的參數新增預設值可能會使此方法在重載呼叫中不可見。
Scala 3 放棄了此區別。具有預設參數的方法不會被視為優先級低於其他方法。