在 GitHub 上编辑此页面

右关联扩展方法:详细信息

扩展方法可以具有的最通用的签名如下

  • 可选类型子句 leftTyParams
  • 可能为空的 using 子句列表 leadingUsing
  • 单个参数 leftParam(在显式 term 子句中)
  • 一个可能为空的 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)

如果 x 是一个纯表达式或按名称调用参数,Scala 编译器会将右结合中缀运算(如 x +: xs)预处理为 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