我正在获取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
转换为String
types。
备注:类实现两个接口时会发生这种错误,两个接口都具有相同签名的扩展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
variablesab
types是简单的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团队来解决。