在 GitHub 上編輯此頁面

右結合擴充方法:詳細資訊

擴充方法可以具有的最通用的簽章如下

  • 選用的類型子句 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 trailingUsingrightTyParam 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