2016-03-01 62 views
9

我有一个简单的工厂模式,其中的实现是通过重载决议确定的。问题在于Kotlin编译器对内联lambda表达式的“Overload resolution ambiguity ..”抱怨。Kotlin:内联lambda和重载分辨率模糊

class Foo(){ 
    companion object Factory { 
     fun create(x: Int, f: (Int) -> Double) = 2.0 
     fun create(x: Int, f: (Int) -> Int) = 1 
    } 
} 

fun main(args:Array<String>){ 
    val a = Foo.create(1,::fromDouble) //OK 
    val b = Foo.create(1,::fromInt) //OK 
    val ambiguous = Foo.create(1){i -> 1.0} //Overload resolution ambiguity? 
} 


fun fromDouble(int:Int) = 1.0 
fun fromInt(int:Int) = 1 

Kotlin编译器如何解决重载解析以及为什么内联lambda被认为是模糊的?

+4

这似乎是一个错误,因为如果我投像'拉姆达{我:诠释 - > 1.0}为(INT) - > Double'没有歧义,但它说,不需要转换。另外,如果我将lambda提取到'val l = {i:Int - > 1.0}'并使用它,再次没有歧义。请在错误跟踪器中搜索此问题,如果它不存在,请提交一个新文件:https://youtrack.jetbrains.com/issues/KT – hotkey

+1

另一个有趣的事情是,如果您将@ lambkey作为@hotkey执行,IDE会告诉你没有必要。但是,当你删除它时,它会抱怨含糊不清。 –

+1

感谢您的输入!认为这可能是一个错误。在https://youtrack.jetbrains.com/issue/KT-11265 –

回答

4

科特林编译器只解析一次表达。 因此,当编译器开始解析lambda表达式时,它应该知道lambda参数的类型。 由于这种编译器应该选择的方法create一个前它开始往里拉姆达。

例子:

fun foo(f: (Int) -> Int) = 1 
fun foo(f: (String) -> String) = "" 
val bar = foo { 
    println(it) 
    5 
} 

在这里我们不能选择的功能foo之一,因为没有他们中的一个更具体的另一个,是因为我们不知道我们无法启动lambda表达式解析键入it

在您的例子是在理论上是可行的选择特定的功能之前就开始为拉姆达分辨率,因为所有潜在功能类型的拉姆达参数是相同的。但这是一个不可思议的逻辑,可能很难实现。

+0

提交报告这是一个无赖。 lambda上的重载解析对数值应用来说非常有用。假设我有一个在float,double和int上工作的矩阵类。对于“重载决议”,实例化将是'val ms = Mat44 {i,j - > 1.0}',现在我不得不写'val ms = Mat44({i:Int,j:Int - > 1.0} Int,Int) - > Double)',这对于这样一个简单的任务来说是简单而愚蠢的。非常感谢@erokhins的一个很好的解释! –

+0

作为解决方法,您可以使用不同的名称创建函数:'fun Mat44Int2Double(f:(Int,Int) - > Double)= Mat44(f)'。但它不是优雅的... – erokhins

+0

是的,有点让我想起旧的ANSI C日子:) –