有什么区别!!和 ?在 kotlin 的空安全中?

Omi*_*miK 0 android kotlin kotlin-null-safety

我对以下实例中?和的用法有点困惑。!!

  lat = mLastLocation?.latitude.toString()
  longi = mLastLocation!!.longitude.toString()
Run Code Online (Sandbox Code Playgroud)

我应该使用哪个空安全运算符?

And*_*lli 5

长话短说:

?.操作员是安全的。当您不确定链的可空性时使用它。 当您确定先前的链运算结果不为空时才
!!.使用运算符。否则,崩溃。

ifmLastLocation永远不会为空,请放心使用!!.(并重新考虑一下您的代码),否则,请使用?.

介绍

在使用 Kotlin 进行编码时,您已经达到了最好(也是最有用)的要点之一。

这里我应该使用哪个空安全运算符?

这取决于您想要实现的行为。在 Kotlin 中,您必须非常具体地了解要如何处理 null 值,因为该语言被设计为开箱即用的 null 安全。当然,针对 JVM给编程语言带来了许多挑战。出现空值的可能性就是其中之一,正如我们将看到的,Kotlin 以一种非常聪明的方式处理这个问题。

目的

我们可以解释这两个运算符背后的完整理论,但我相信一个例子就足够了。
假设您有一个名为 的类Location,我们将在可为 null 的变量中声明它。在 Kotlin 中,这表示为val location: Location? 假设Location类有一个名为 的属性lat,它是一个可为空的字符串和一个lon不可为空的字符串。

data class User(val lat: String?, val lon: String)
Run Code Online (Sandbox Code Playgroud)

操作员?.

Kotlin 安全调用操作符文档

该操作员是安全呼叫操作员。
如果您在调用链中使用它,它会检查您的代码链是否在前一个元素不为空的情况下进入下一个元素。否则,将从语句中返回 null。

val location: Location? = getLocation()
println(location.lat)      // Compile-time error.
println(location?.lat)    // Works fine.
Run Code Online (Sandbox Code Playgroud)

发生这种情况是因为在第一种情况下,前面的对象?.可以为空,因此 Kotlin 编译器推断访问可为空的属性可能会导致 NPE。

location可以为空或非空。
我们只是不知道它会是什么,并且 Kotlin 环境严格确保您正在处理该值为 null 的可能性,因为我们的引用变量的类型被定义为可为 null。

然而,某个变量为 null 是开发人员可能不知道的事情。有时,您甚至不需要接收 null 或非 null 值。

在这种情况下,您可以安全地坚持使用?,因为如果您不确定所引用的内容是否将为空,那么您知道该运算符是您的朋友。

val location: Location = getSafeLocation()
val nullableLocation: Location? = getLocation()

// Fine, may print "null" or the value, if present. 
// println accepts nullable values
println(location.lar) 

// 100% sure it'll print the corrisponding String value
println(location.lon)

// May print "null", "null", or the lat String value.
// The first "null" is because the ? operator will check if
// nullableLocation is null. If it is, it stops the execution
// chain and returns null. Otherwise, it assumes nullableLocation is safe
// and goes on.
//
// The second "null" is because the value itself of lat
// is declared as String? and Kotlin knows it may be null.
// If println() did not accept null values, this call would fail,
// but instead it prints "null" in case lat is indeed null.
println(nullableLocation?.lat)

// Since lat was the last element of the chain, it is not
// delivered as the parameter type anymore, and thus if we
// want to read a property from it we have to ensure that it isn't null.
println(nullableLocation?.lat?.length)

// This, as you may guess, returns wither null in case nullableLocation is null,
// otherwise 100% sure it will print lon value, since it is not a String? but a String.
println(nullableLocation?.lon)
Run Code Online (Sandbox Code Playgroud)

操作员!!.

Kotlin Double-Bang 运算符文档

这就是可怕的双爆炸运算符。说到语法,它与 非常相似?.,因为它用在同一个地方。

用一种非常简单的方式描述它:如果调用之前有任何内容为空,您的代码就会崩溃。即刻。没有警告。你!!.明确地说

Kotlin 必须忽略任何类型可为空标记并执行您想要的操作,即使它进入了某种危险区域。这称为强制力,因为您迫使 Kotlin 环境相信前面的语句不为空。该运算符的最佳用例是在将另一个库移植到 Kotlin 时,或者在处理 API RESTful 响应时,可能会出现 null 值,但由于环境/平台原因,您知道某些值不能为 null。如果使用得当,这可以帮助您首先在 Kotlin 世界中引入类型安全。

但对于主流软件来说,此功能适用于非常具体且狭窄的用途:如果您 100% 确定先前的调用不为,请继续。

val location: Location? = getLocation()
println(location!!.lon)
Run Code Online (Sandbox Code Playgroud)

如果位置是,前面的代码可能会崩溃

使用哪一个

两个运算符都是类型转换的。它们都将可空值转换为不可空值。做事的方式是变化的因素。

作为一般规则,如果您确定目标值不为空,请使用!!.,否则坚持使用?.