我在kotlin安全通话中遇到过载分辨率模糊错误

问题描述 投票:12回答:5

我有一个可以为空的字符串变量ab。如果我在给它分配null之后通过安全调用操作符调用toUpperCase,kotlin会给出错误。

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

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

这有什么问题?

kotlin nullable
5个回答
6
投票

正如本doc about smart-casts所述:

x = y使赋值后的y类型为x

线ab = null可能聪明的铸造abNothing?。如果你检查ab is Nothing?它确实是true

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

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


Remarks: This kind of error will occur when a class implements two interfaces and both interface have extension function of the same signature:
//interface
interface A {}
interface B {}

//extension function
fun A.x() = 0
fun B.x() = 0

//implementing class
class C : A, B {}

C().x()    //Overload resolution ambiguity
(C() as A).x()    //OK. Call A.x()
(C() as B).x()    //OK. Call B.x()

2
投票

这看起来真的像个bug。在分配String?时,类型null以某种方式丢失,所以你必须明确地告诉编译器它应该处理String?

fun main(args: Array<String>){
    var ab: String? = "hello"
    ab = null
    println((ab as String?)?.toUpperCase()) // explicit cast

    // ...or

    println(ab?.let { it.toUpperCase() }) // use let
}

2
投票

我不确定,但由于智能投射(对Nothing?,每种可空类型的子类型),这似乎是一个错误。这个工作:

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

fun makeNull(): String? = null

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


1
投票

我相信这是由于Kotlin使用的smart casts。换句话说,Kotlin能够推断出这行代码:

ab = null

变量ab的类型只是null(这不是你可以在Kotlin中使用的实际类型 - 我只是指允许值的范围),而不是String?(换句话说,没有办法ab可能包含String)。

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

要避免这种行为,请查看其他人提出的答案(例如显式转换为String?),但这绝对看起来像一个功能(而且非常有用),而不是我的错误。


1
投票

我反编译你的功能,我想:在你制作ab = null之后,编译器将智能播放它,将null (ACONST_NULL)放在ab的每一个版本中。然后因为null没有类型。你不能推断toUpperCase()接收器的类型。

这是从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团队解决。

© www.soinside.com 2019 - 2024. All rights reserved.