方法调用的隐式对象的Scala优先级

时间:2013-02-28 00:25:41

标签: scala

我们说我有以下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'
                ^

因为&#39; +&#39;已经存在于Char类型中,我认为隐式转换不会发生。有没有办法覆盖默认行为并应用&#39; +&#39;在申请Char类型之前转换的期限?

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

1 个答案:

答案 0 :(得分:4)

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

<强>更新: 管理隐式转换的精确规则在Scala Language Specification

中定义
  

视图适用于三种情况。

     
      
  1. 如果表达式e是T类型,并且T不符合表达式   预期类型在这种情况下,搜索适用于的隐式v   e,其结果类型符合pt。搜索按照的情况进行   隐式参数,其中隐式范围是T =&gt;的隐式范围。 PT。如果这样的话   找到视图,表达式e被转换为v(e)。
  2.   
  3. 如果选择器m不表示成员,则选择e为具有类型T的e   of。在这种情况下,搜索适用于e及其结果的视图v   包含一个名为m的成员。搜索按照隐式的情况进行   参数,其中隐式范围是T的一个。如果找到这样的观点,   选择e.m转换为v(e).m。
  4.   
  5. 在e类型为T的选择e.m(args)中,如果选择器m表示T的某些成员,但这些成员都不适用于参数args。在   在这种情况下,搜索适用于e的视图v,其结果包含适用于args的方法m。搜索按照中的进行   隐式参数的情况,其中隐式范围是T的一个。如果这样的话   如果找到视图,则选择e.m将转换为v(e).m(args)。
  6.   

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

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

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

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

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

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