2010-07-23 64 views
11

this class在斯卡拉:为什么Scala类型推断在这里失败?

object Util { 
    class Tapper[A](tapMe: A) { 
    def tap(f: A => Unit): A = { 
     f(tapMe) 
     tapMe 
    } 

    def tap(fs: (A => Unit)*): A = { 
     fs.foreach(_(tapMe)) 
     tapMe 
    } 
    } 

    implicit def tapper[A](toTap: A): Tapper[A] = new Tapper(toTap) 
} 

现在,

"aaa".tap(_.trim) 

不能编译,给人错误

error: missing parameter type for expanded function ((x$1) => x$1.trim)

为什么没有类型推断为String?从错误看来,隐式转换确实会触发(否则错误将沿着“tap不是类String的成员”)。看起来转换必须是Tapper[String],这意味着参数的类型是String => Unit(或(String => Unit)*)。

有趣的是,如果我注释掉或者tap定义,那么它会进行编译。

回答

17

6.26.3 Overloading Resolution

One first determines the set of functions that is potentially applicable based on the shape of the arguments

...

If there is precisely one alternative in B, that alternative is chosen.

Otherwise, let S1, . . . , Sm be the vector of types obtained by typing each argument with an undefined expected type.

tap两种过载是可能适用的(基于的参数“形状”,其占元数和类型构造功能N)。

所以类型确定收益,因为它将:

val x = _.trim 

和失败。

更聪明的算法可以采用每个备选方案的相应参数类型的最小上限,并将其用作预期类型。但是这种复杂性并不值得,国际海事组织。重载有很多转角的情况,这是另一回事。

但是有可以在此情况下,使用一个小技巧,如果你真的需要接受单个参数的重载:

object Util { 
    class Tapper[A](tapMe: A) { 
    def tap(f: A => Unit): A = { 
     f(tapMe) 
     tapMe 
    } 

    def tap(f0: A => Unit, f1: A => Unit, fs: (A => Unit)*): A = { 
     (Seq(f0, f1) ++ fs).foreach(_(tapMe)) 
     tapMe 
    } 
    } 

    implicit def tapper[A](toTap: A): Tapper[A] = new Tapper(toTap) 

    "".tap(_.toString) 
    "".tap(_.toString, _.toString) 
    "".tap(_.toString, _.toString, _.toString) 
} 
+0

好主意,谢谢!我想我必须以不同的方式命名它们。 – 2010-07-23 08:54:03

+3

你很快成为新的丹尼尔,杰森! – 2010-07-23 14:25:38

+2

@oxbow更好的是,他经常引用规范,这是一件好事。 – 2010-07-23 15:50:18

相关问题