模棱两可的重载甚至更具体

时间:2019-06-16 20:57:38

标签: scala single-abstract-method

我对foo有两个定义,其中一个更具体一些

def foo(f: java.util.function.ToIntFunction[String]) = println("foo1")
def foo[T](f: String=>T) = println("foo2")
//def foo[T](f: String=>T)(implicit d: DummyImplicit) = println("foo2")    //Does not work either


foo({_: String => 1})            //Should pick foo1, but gives error instead

错误是:

error: ambiguous reference to overloaded definition,
both method foo in object Main of type [T](f: String => T)Unit
and  method foo in object Main of type (f: java.util.function.ToIntFunction[String])Unit

我也尝试了DummyImplicit的把戏,但仍然给出相同的错误。在Int出现而没有使用反射的情况下,如何实现编译时间过载?

我正在使用具有SAM类型支持的Scala 2.12。


修改

我希望获得一种不限于使用Java转换器的解决方案,因为ToIntFunction接口可以用Scala特性代替,例如

trait ToIntFunction[T] { def apply(v: T): Int }
def foo(f: ToIntFunction[String]) = println("foo1")
def foo[T](f: String=>T) = println("foo2")

我认为这是方法重载的更普遍的问题。

2 个答案:

答案 0 :(得分:1)

在装有Scala 2.12的计算机上,foo({_: String => 1})的评估结果为foo2,因此我无法重现该问题。我在Scala 2.12中对SAM conversion in overloading resolution的解释是,Function类型的参数具有优先权,因此应求值为foo2

  

为了提高源兼容性,重载分辨率具有   适应于首选带有函数类型参数的方法   SAM类型参数的方法。

注意_: String => 1Function1。要强制其评估为foo1,请尝试从scala-java8-compatasJava像这样:

import scala.compat.java8.FunctionConverters._
foo({_: String => 1}.asJava) // foo1

根据KrzysztofAtłasik的评论,它可以在Scala 2.13中重现。

答案 1 :(得分:1)

我找到了使用宏扩展的解决方案:

object Foo {
    import scala.reflect.macros.Context
    import scala.language.experimental.macros

    def foo[T,R](f: T=>R) = macro fooImpl[T,R]

    def fooImpl[T: c.WeakTypeTag, R: c.WeakTypeTag](c: Context)
        (f: c.Expr[T=>R]): c.Expr[Unit] = {
        import c.universe._
        if(c.weakTypeOf[R] == c.weakTypeOf[Int]) {
            reify { println("Int") }
        }
        else {
            reify { println("Not Int") }
        }
    }
}

在另一个文件中,

object Test extends MainApp {
  Foo.foo {_:String => 0}    //expands into a simple println and it prints "Int"
  Foo.foo {_:String => 0d}   //prints "Not Int"
}

这绝对不是理想的,但是可以解决问题。希望有人不用使用宏就可以给出答案。