0

假设我有以下 scala 代码:

case class Term(c:Char) {
   def unary_+ = Plus(this)
}

case class Plus(t:Term)

object Term {
  implicit def fromChar(c:Char) = Term(c) 
}

现在我从 scala 控制台得到这个:

scala> val p = +'a'
p: Int = 97

scala> val q:Plus = +'a'
<console>:16: error: type mismatch;
found   : Int
required: Plus
   val q:Plus = +'a'
                ^

因为 '+' 已经存在于 Char 类型上,所以我认为不会发生隐式转换。在应用于 Char 类型之前,有没有办法覆盖默认行为并在转换后的 Term 上应用“+”?

(顺便说一句,这个例子是人为的,我不是在寻找替代设计。这个例子只是为了说明问题)

4

1 回答 1

4

不,没有办法覆盖默认+运算符,即使是隐式转换也是如此。当遇到未在接收对象上定义的运算符(实际上是方法,因为运算符只是普通方法)时,编译器将寻找到对象的隐式转换以提供此运算符。但是如果操作符已经在目标对象上定义了,它永远不会查找任何转换,原始的操作符总是会被调用。因此,您应该定义一个单独的运算符,其名称不会与任何先前存在的运算符冲突。

更新:控制隐式转换的精确规则在Scala 语言规范中定义:

视图适用于三种情况。

  1. 如果表达式 e 的类型为 T ,并且 T 不符合表达式的预期类型 pt。在这种情况下,搜索适用于 e 并且其结果类型符合 pt 的隐式 v。搜索与隐式参数的情况一样进行,其中隐式范围是 T => pt 之一。如果找到这样的视图,则表达式 e 将转换为 v(e)。
  2. 在类型为 T 的 e 选择 em 中,如果选择器 m 不表示 T 的成员。在这种情况下,搜索适用于 e 并且其结果包含名为 m 的成员的视图 v。搜索与隐式参数的情况一样进行,其中隐式范围是 T 之一。如果找到这样的视图,则将选择 em 转换为 v(e).m。
  3. 在类型为 T 的 e 的选择 em(args) 中,如果选择器 m 表示 T 的某些成员,但这些成员都不适用于参数 args。在这种情况下,搜索适用于 e 的视图 v,其结果包含适用于 args 的方法 m。搜索与隐式参数的情况一样进行,其中隐式范围是 T 之一。如果找到这样的视图,则将选择 em 转换为 v(e).m(args)。

换句话说,隐式转换发生在 3 种情况下:

  1. 当表达式是类型但在预期T不相关类型的上下文中使用时,将应用从to的隐式转换(如果任何此类转换在范围内)。T'TT'

  2. 当试图访问该对象上不存在的对象成员时,将应用从该对象到另一个具有该成员的对象的隐式转换(如果任何此类转换在范围内)。

  3. 当尝试使用不匹配任何相应重载的参数列表调用对象的方法时,编译器会应用从该对象到另一个对象的隐式转换,该对象确实具有该名称的方法并具有兼容的参数列表(如果任何此类转换在范围内)。

    请注意,这实际上不仅仅适用于方法(具有apply方法的内部对象/val 也符合条件)。另请注意,Randall Schulz 在下面的评论中谈到了这种情况。

因此,在您的情况下,第 (2) 和 (3) 点是相关的。鉴于您要定义一个名为 的方法unary_+,该方法已经存在于 typeInt中,情况 (2) 不会启动。并且鉴于您的版本与内置Int.unary_+方法具有相同的参数列表(它们都是无参数的),点(3) 也不会踢。因此,您绝对不能定义将重新定义的隐式unary_+.

于 2013-02-28T00:49:06.457 回答