我正在获取Kotlin安全调用的重载解析模糊错误

我有一个可以为空的字符串variablesab 。 如果我在给它赋值为null之后通过安全调用操作符来调用UpperCase,kotlin会给出错误。

 fun main(args: Array){ var ab:String? = "hello" ab = null println(ab?.toUpperCase()) } 

错误:(6,16)
重载分辨率模糊性:
@InlineOnly public inline fun Char.toUpperCase():在kotlin.text中定义的字符
@InlineOnly public inline fun String.toUpperCase():在kotlin.text中定义的字符串

这里有什么问题?

正如本文关于智能演员所述 :

x = y使赋值后y的types为x

ab = null可能智能转换为Nothing? 。 如果你检查ab is Nothing? 确实true

 var ab: String? = "hello" ab = null println(ab?.toUpperCase()) println(ab is Nothing?) // true 

由于Nothing? 是所有types的子types(包括Char?String? ),它解释了为什么你会得到Overload resolution ambiguity错误。 这个错误的解决方案是Willi Mentzel在答案中提到的,在调用toUpperCase()之前将ab转换为Stringtypes。


备注:类实现两个接口时会发生这种错误,两个接口都具有相同签名的扩展function:

 //interface interface A {} interface B {} //extension function fun Ax() = 0 fun Bx() = 0 //implementing class class C : A, B {} C().x() //Overload resolution ambiguity (C() as A).x() //OK. Call Ax() (C() as B).x() //OK. Call Bx() 

这真的好像是一个错误。 String?typesString? 在分配null会丢失,所以你必须明确地告诉编译器它应该处理一个String?

 fun main(args: Array){ var ab: String? = "hello" ab = null println((ab as String?)?.toUpperCase()) // explicit cast // ...or println(ab?.let { it.toUpperCase() }) // use let } 

我不确定,但这似乎是一个错误,由于智能铸造(到Nothing? ,每个可空types的子types)。 这个工作:

 fun main(args: Array) { var ab: String? = "hello" ab = makeNull() println(ab?.toUpperCase()) } fun makeNull(): String? = null 

唯一的区别是:编译器不直接知道null赋值,这似乎会导致您的示例中的错误。 但是,你的工作也许也应该工作。

我相信这是由于Kotlin使用的聪明的演员 。 换句话说,Kotlin能够推断出这行代码之后:

 ab = null 

variablesabtypes是简单的null (这不是你可以在Kotlin中使用的实际types – 我只是指的是允许值的范围),而不是String? (换句话说, 没有办法 ab可能包含一个String )。

考虑到toUpperString()扩展函数是仅为Char和String(而不是Char?或String?)定义的,因此无法在它们之间进行选择。

为了避免这种行为,看到其他人提出的答案(如显式转换为字符串?),但这绝对看起来像一个function(而非常有用),而不是我的错误。

我反编译你的函数,我想:在你做出ab = null的那一刻,编译器会对它进行smartcast,在每个ab中都放置null (ACONST_NULL) 。 那么因为null没有types。 你不能推断toUpperCase()的接收者的types。

这是从kotlin字节码生成的java等效代码:

 public final void main(@NotNull String[] args) { Intrinsics.checkParameterIsNotNull(args, "args"); String ab = "hello"; ab = (String)null; Object var3 = null; System.out.println(var3); } 

这看起来应该由kotlin团队来解决。