我对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")
我认为这是方法重载的更普遍的问题。
答案 0 :(得分:1)
在装有Scala 2.12的计算机上,foo({_: String => 1})
的评估结果为foo2
,因此我无法重现该问题。我在Scala 2.12中对SAM conversion in overloading resolution的解释是,Function
类型的参数具有优先权,因此应求值为foo2
:
为了提高源兼容性,重载分辨率具有 适应于首选带有函数类型参数的方法 SAM类型参数的方法。
注意_: String => 1
是Function1
。要强制其评估为foo1
,请尝试从scala-java8-compat的asJava
像这样:
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"
}
这绝对不是理想的,但是可以解决问题。希望有人不用使用宏就可以给出答案。