右結合擴充方法:詳細資訊
擴充方法可以具有的最通用的簽章如下
- 選用的類型子句
leftTyParams
- 可能為空的 using 子句清單
leadingUsing
- 單一參數
leftParam
(在明確的項目子句中) - 可能為空的 using 子句清單
trailingUsing
- 名稱(前面加上
def
關鍵字) - 選用的類型子句
rightTyParams
- 選用的單一參數
rightParam
(在明確的項目子句中) - 任何數量的任何子句
rest
例如
extension [T] // <-- leftTyParams
(using a: A, b: B)(using c: C) // <-- leadingUsing
(x: X) // <-- leftParam
(using d: D) // <-- trailingUsing
def +:: [U] // <-- rightTyParams
(y: Y) // <-- rightParam
(using e: E)(z: Z) // <-- rest
如果擴充方法名稱以 :
結尾,且緊接著單一明確的項目參數(換句話說,rightParam
存在),則會將其視為右關聯運算子(如 SLS §6.12.3 所述)。在上述範例中,該參數為 (y: Y)
。
Scala 編譯器會預先處理右結合中綴運算,例如 x +: xs
,如果 x
是純粹表達式或按名稱呼叫參數,則預先處理為 xs.+:(x)
,否則預先處理為 val y = x; xs.+:(y)
。這是必要的,因為常規右結合中綴方法是在其右運算元的類別中定義的。為了彌補這個交換,右結合擴充方法的展開會執行反向參數交換。更精確地說,如果 rightParam
存在,則擴充方法展開的總參數順序是
leftTyParams leadingUsing rightTyParams rightParam leftParam trailingUsing rest
換句話說,我們將 leftParams trailingUsing
與 rightTyParam rightParam
交換。
例如,上面的 +::
方法將變為
<extension> def +:: [T]
(using a: A, b: B)(using c: C)
[U]
(y: Y)
(x: X)
(using d: D)
(using e: E)(z: Z)
在撰寫具有參數間依賴關係的右結合擴充方法時,必須記住這個展開。
這個展開在以非中綴形式呼叫擴充方法時也會引入一些不一致性。使用者需要手動反轉呼叫位置的引數順序。例如
extension [T](x: T)
def *:(xs: List[T]): List[T] = ...
y.*:(ys) // error when following the parameter definition order
ys.*:(y)
*:(y)(ys) // error when following the parameter definition order
*:(ys)(y)
這個表示法的另一個限制是無法明確傳遞 def
的類型參數(除非以字首形式呼叫)。例如
extension (x: Int)
def *:[T](xs: List[T]): List[T] = ...
xs.*:[Int](1) // error when trying to set T explicitly
右結合擴充方法的展開也會影響可以明確傳遞上下文參數的順序。
群組擴充也可能表現得不合直覺,一般來說,群組中的所有擴充都是接收者的擴充。除非其中一個擴充是右結合擴充方法,這種情況下,它是一個對其引數類型的擴充。例如
extension (a: Int)
def :+(b: Long): Long = ... // extension on Int
def +:(b: Long): Long = ... // extension on Long