我在kotlin安全通话

时间:2017-12-19 10:30:52

标签: kotlin nullable

我有一个可以为空的字符串变量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中定义的字符串

这里有什么问题?

5 个答案:

答案 0 :(得分:6)

doc about smart-casts中所述:

  

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