0

这个科特林代码:

fun badKotlin(text: String?): Boolean {
    if (text == null) {
        return true
    }

    var temp = text
    if (false) {
        temp = Arrays.deepToString(arrayOf(text))
    } 

    return temp.isBlank() // <-- only safe (?.) or non null asserted (!!.) calls
}

不编译消息:only safe (?.) or non null asserted (!!.) calls are allowed on a nullable receiver of type String?

但如果我添加else

fun badKotlin(text: String?): Boolean {
    if (text == null) {
        return true
    }

    var temp = text
    if (false) {
        temp = Arrays.deepToString(arrayOf(text))
    } else {
        temp = Arrays.deepToString(arrayOf(text))
    }

    return temp.isBlank()
}

全部编译。那么,为什么类型推断会失败呢?

如果我将临时类型更改var temp: String = text为成功编译!因此,此外,如果我们像这样更改 temp 的分配:temp = String.format("%s", text)它也会被编译。

更新:

编译成功:

fun badKotlin(text: String?): Boolean {
    if (text == null) {
        return true
    }

    var temp = text
    if (false) {
        temp = String.format("%s", text)
    } 

    return temp.isBlank() // <-- only safe (?.) or non null asserted (!!.) calls
}

和这个:

fun badKotlin(text: String?): Boolean {
    if (text == null) {
        return true
    }

    var temp: String = text
    if (false) {
        temp = Arrays.deepToString(arrayOf(text))
    } 

    return temp.isBlank() // <-- only safe (?.) or non null asserted (!!.) calls
}
4

2 回答 2

2

你可能会想,之后

if (text == null) {
    return true
}

的类型text被细化为String而不是String?

但似乎不是;相反,当编译器看到在需要textaString的地方使用时,它会插入一个智能转换。在里面

var temp = text

行没有理由插入强制转换,所以编译器没有,并且类型tempString?.

如果你写

var temp: String = text

强制转换必要的,因此编译器会插入它。

如果你写

if (...) {
    temp = Arrays.deepToString(arrayOf(text))
} else {
    temp = Arrays.deepToString(arrayOf(text))
}

编译器看到无论发生什么,temp都被分配了一个平台类型String!的值,该值可以再次智能转换为String. 没有else分支,这不会发生。

编辑:

奇怪的是,如果你只是删除if并离开

fun badKotlin(text: String?): Boolean {
    if (text == null) {
        return true
    }

    var temp = text
    
    return temp.isBlank()
}

它确实编译,如果我的解释是完整的,我不会期望它。所以编译器确实维护了智能转换所需的信息,但它似乎没有被应用,因为

更具体地说,智能演员根据以下规则适用: ...

  • var局部变量 -如果变量在检查和使用之间没有被修改,则不会在修改它的 lambda 中捕获,并且不是局部委托属性;

在这种if-else情况下,两个分支中的分配一起作为另一个检查;在if-only 中,一个分支没有。

于 2018-03-13T06:49:24.063 回答
1

通过分配textto temp, temp 的类型也将变为String?。像这样:

var temp: String? = text

由于您if (false)将永远不会被执行,因此它对代码没有任何影响。else添加一个总是被执行的块(因为它基本上意味着)if (true)并分配一个不可为空String的a 。temp由于 temp 在第二个示例中不可为空,因此您不必再使用安全调用运算符...

于 2018-03-13T04:15:32.300 回答