我有一个可以为空的字符串变量ab
。如果我在为其指定null后通过安全调用操作符调用toUpperCase
,则kotlin会给出错误。
fun main(args: Array<String>){
var ab:String? = "hello"
ab = null
println(ab?.toUpperCase())
}
错误:(6,16)
过载分辨率模糊:
@InlineOnly公开 内联乐趣Char.toUpperCase():在kotlin.text中定义的char @InlineOnly public inline fun String.toUpperCase():在kotlin.text中定义的字符串
这里有什么问题?
答案 0 :(得分:6)
x = y使得赋值后的y类型为x
ab = null
行可能会智能地将ab
投射到Nothing?
。如果您检查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()
的类型。
//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()
答案 1 :(得分:2)
我不确定,但由于智能投射(至Nothing?
,每个可空类型的子类型),这似乎是一个错误。这个有效:
fun main(args: Array<String>) {
var ab: String? = "hello"
ab = makeNull()
println(ab?.toUpperCase())
}
fun makeNull(): String? = null
唯一的区别是:编译器不直接知道null
赋值,这似乎会导致示例中的错误。但是,你的应该也应该工作。
答案 2 :(得分:2)
这看起来真是个错误。类型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
}
答案 3 :(得分:1)
我认为这是由于Kotlin使用的smart casts。换句话说,Kotlin能够推断出这行代码:
ab = null
变量类型ab
只是null
(这不是您可以在Kotlin中使用的实际类型 - 我只是指允许值的范围),而不是String?
(在其他单词,无法 ab
可能包含String
。)
考虑到toUpperString()扩展函数仅为Char和String(而不是Char?或String?)定义,因此无法在它们之间进行选择。
要避免这种行为,请看其他人提出的答案(例如显式转换为String?),但这绝对看起来像一个功能(而且非常有用),而不是我的错误。
答案 4 :(得分: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团队解决。