简体   繁体   English

在 Kotlin 中使用安全调用运算符对类似代码的不同结果

[英]Different results on similar code with safe call operator in Kotlin

I'm new to Kotlin and these two below codes give different results.我是 Kotlin 的新手,下面这两个代码给出了不同的结果。

fun main() {
  var name: String? = "Rajat"
  name = null
  print(name?.toLowerCase())
}

Output: Compilation Error (illegal access operation)输出:编译错误(非法访问操作)

fun main() {
  var name: String? = null
  print(name?.toLowerCase())
}

Output: null输出:空

When you do this assignment:当你做这个任务时:

name = null

name is smart casted to Nothing? name是聪明的,什么都Nothing? , which is problematic. ,这是有问题的。 Nothing is the subtype of every type, and so you become able to call any accessible extension functions of any type, according to the overload resolution rules here . Nothing是每种类型的子类型,因此您可以根据此处的重载决策规则调用任何类型的任何可访问扩展函数。

Compare:相比:

fun main() {
    var name: String? = "Denis"
    name = null
    print(name?.myExtension()) // works

    val nothing: Nothing? = null
    print(nothing?.myExtension()) // also works
}

fun Int.myExtension(): Nothing = TODO()

Note that allowing you to call any extension function on Nothing is perfectly safe - name is null anyway, so nothing is actually called.请注意,允许您在Nothing上调用任何扩展函数是非常安全的 - name无论如何都是 null,因此实际上没有调用任何内容。

Char.toLowerCase and String.toLowerCase happen to be two of the extension functions that are accessible, and you can call both on name , which is now a Nothing? Char.toLowerCaseString.toLowerCase恰好是两个可访问的扩展函数,您可以在name上调用这两个函数,现在是Nothing? . . Therefore, the call is ambiguous.因此,调用是模棱两可的。

Note that smart casts only happens in assignments, not in initialisers like var name: String? = null请注意,智能转换只发生在赋值中,而不是像var name: String? = null这样的初始化器中。 var name: String? = null . var name: String? = null Therefore, name is not smart casted to Nothing?因此, name是不是很聪明地转换为Nothing? in this case:在这种情况下:

fun main() {
    var name: String? = null
    print(name?.toLowerCase()) // better to use lowercase(), toLowerCase is deprecated!
}

For the reason why, see my answer here .至于原因,请看我的回答here

The actual error on your first example is第一个示例的实际错误是

Overload resolution ambiguity: public inline fun Char.toLowerCase(): Char defined in kotlin.text public inline fun String.toLowerCase(): String defined in kotlin.text重载解析歧义:public inline fun Char.toLowerCase():在 kotlin.text 中定义的字符 public inline fun String.toLowerCase():在 kotlin.text 中定义的字符串

Looks like the Kotlin compiler is being too smart for its own good here.看起来 Kotlin 编译器在这里太聪明了。 What's happening, is that on the second example, you are explicitly defining a variable of type String?发生了什么,在第二个示例中,您明确定义了一个String? and assigning it some value ( null in this case, but that doesn't matter).并为其分配一些值(在这种情况下为null ,但这没关系)。

On the second example, you are defining a variable of some type, and then telling the compiler "hey, after this assignment, name is always null ".在第二个示例中,您正在定义某种类型的变量,然后告诉编译器“嘿,在此分配之后, name始终为null ”。 So then it remembers the more-specific " name is null " instead of " name is String? ".那么它会记住更具体的“ name is null ”而不是“ name is String? ”。

The standard library has two methods called toLowerCase , one on Char and one on String .标准库有两种称为toLowerCase的方法,一种在Char上,另一种在String上。 Both of them are valid matches now, and the compiler is telling you it doesn't know which one to pick.它们现在都是有效匹配,编译器告诉你它不知道选择哪一个。 In the end that won't matter, because name is null , but the compiler apparently doesn't use that final thing to throw out the method call altogether.最后没关系,因为namenull ,但编译器显然没有使用最后的东西来完全抛出方法调用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM