简体   繁体   English

为什么Scala类型推断在这里失败?

[英]Why does Scala type inference fail here?

I have this class in Scala: 我在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)
}

Now, 现在,

"aaa".tap(_.trim)

doesn't compile, giving the error 不编译,给出错误

error: missing parameter type for expanded function ((x$1) => x$1.trim) 错误:扩展函数缺少参数类型((x $ 1)=> x $ 1.trim)

Why isn't the type inferred as String ? 为什么不将类型推断为String From the error it seems that the implicit conversion does fire (otherwise the error would be along the lines of " tap is not a member of class String "). 从错误看来,隐式转换似乎触发了(否则错误将沿着“ tap不是类String的成员”的行)。 And it seems the conversion must be to Tapper[String] , which means the type of the argument is String => Unit (or (String => Unit)* ). 似乎转换必须是Tapper[String] ,这意味着参数的类型是String => Unit (或(String => Unit)* )。

The interesting thing is that if I comment out either of tap definitions, then it does compile. 有趣的是,如果我注释掉任何一个tap定义,那么它就会编译。

6.26.3 Overloading Resolution 6.26.3重载分辨率

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. 如果B中恰好有一个替代方案,则选择该替代方案。

Otherwise, let S1, . 否则,让S1 ,. . . , Sm be the vector of types obtained by typing each argument with an undefined expected type. ,Sm是通过键入具有未定义的期望类型的每个参数而获得的类型的向量。

Both overloads of tap are potentially applicable (based on the 'shape' of the arguments, which accounts for the arity and type constructors FunctionN). tap两个重载都可能适用(基于参数的'形状',它考虑了arity和类型构造函数FunctionN)。

So the typer proceeds as it would with: 因此,typer继续如下:

val x = _.trim

and fails. 并失败。

A smarter algorithm could take the least upper bound of the corresponding parameter type of each alternative, and use this as the expected type. 更智能的算法可以采用每个备选方案的相应参数类型的最小上限,并将其用作期望类型。 But this complexity isn't really worth it, IMO. 但这种复杂性并不值得,IMO。 Overloading has many corner cases, this is but another. 重载有很多极端情况,这只是另一种情况。

But there is a trick you can use in this case, if you really need an overload that accepts a single parameter: 但是在这种情况下你可以使用一个技巧,如果你真的需要一个接受单个参数的重载:

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)
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM