为什么Scala类型推断在这里失败? [英] Why does Scala type inference fail here?

查看:130
本文介绍了为什么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)
}

现在

"aaa".tap(_.trim)

无法编译,提示错误

错误:扩展功能缺少参数类型((x $ 1)=> x $ 1.trim)

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

为什么类型不能推断为String?从该错误看来,隐式转换确实会触发(否则该错误将类似于"tap不是类String的成员").似乎必须转换为Tapper[String],这意味着参数的类型为String => Unit(或(String => Unit)*).

Why isn't the type inferred as 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"). And it seems the conversion must be to Tapper[String], which means the type of the argument is String => Unit (or (String => Unit)*).

有趣的是,如果我注释掉定义中的 ,那么它将编译.

The interesting thing is that if I comment out either of tap definitions, then it does compile.

推荐答案

6.26.3重载分辨率

首先确定一组 潜在的功能 适用于根据形状 争论

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

...

如果只有一种选择 在B中,选择了该替代方法.

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

否则,让S1,. . . ,Sm是 通过键入获得的类型的向量 每个带有未定义参数的参数 预期的类型.

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

tap的两个重载都可能适用(基于参数的形状",这说明了Arity和类型构造函数FunctionN).

Both overloads of tap are potentially applicable (based on the 'shape' of the arguments, which accounts for the arity and type constructors FunctionN).

因此,键入程序将继续执行以下操作:

So the typer proceeds as it would with:

val x = _.trim

并且失败.

更聪明的算法可以采用每个替代方法的对应参数类型的最小上限,并将其用作期望的类型.但是,IMO确实不值得这种复杂性.重载有很多极端的情况,但这是另一个.

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

这篇关于为什么Scala类型推断在这里失败?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆