如何将可空类型传递给采用非空类型的函数?
How to pass nullable type into function that takes a non null type?
如果我在通过之前进行空检查,这可能吗?例如:
fun main(args: Array<String>) {
var num: Int? = null
// Stuff happens that might make num not null
...
if (num != null) doSomething(num)
}
fun doSomething(number: Int) {
...
}
我不明白为什么编译器不允许我传递可空值,即使我先检查它不为空。谁能解释一下?
注意:从编译器版本 1.0 beta 开始,相关代码按原样运行
编译器可以判断变量是否在检查和使用之间发生了变化,至少在这个问题中的局部变量以及其他一些情况下是这样。有关详细信息,请参阅 。
http://kotlinlang.org/docs/reference/null-safety.html#checking-for-null-keyword--in-conditions 说
The compiler tracks the information about the [null] check ... this only works where b is immutable (i.e. a local val or a member val which has a backing field and is not overridable), because otherwise it might happen that b changes to null after the check.
所以像这样的东西应该可以工作:
fun main(args: Array<String>) {
var num: Int? = null
// Stuff happens that might make num not null
...
val numVal: Int? = num
if (numVal != null) doSomething(numVal)
}
fun doSomething(number: Int) {
...
}
当然,重写 "stuff happens" 会更好,这样一开始就可以将 num
变成 val
。
在当前的 Kotlin(1.0 测试版或更新版本)中,您不再遇到此问题。你的代码会编译。 val
或 var
的局部变量可以安全地 Smart Cast 因为编译器可以确定该值是否可能已经发生变化(例如在另一个线程上)。
以下是 的摘录,其中涵盖了可空性的更多方面以及处理这些问题的 Kotlin 运算符。
有关 null
检查和智能转换的更多信息
如果您使用 null
检查保护对可空类型的访问,编译器将 smart cast 语句主体中的值不可为空。有一些复杂的流程是不可能发生这种情况的,但对于常见情况来说效果很好。
val possibleXyz: Xyz? = ...
if (possibleXyz != null) {
// allowed to reference members:
possiblyXyz.foo()
// or also assign as non-nullable type:
val surelyXyz: Xyz = possibleXyz
}
或者,如果您执行 is
检查不可空类型:
if (possibleXyz is Xyz) {
// allowed to reference members:
possiblyXyz.foo()
}
对于同样安全转换的 'when' 表达式也是如此:
when (possibleXyz) {
null -> doSomething()
else -> possibleXyz.foo()
}
// or
when (possibleXyz) {
is Xyz -> possibleXyz.foo()
is Alpha -> possibleXyz.dominate()
is Fish -> possibleXyz.swim()
}
有些东西不允许 null
检查到 smart cast 以便以后使用变量。上面的示例使用了一个局部变量,该变量绝不会在应用程序的流程中发生变异,无论是 val
还是 var
,该变量都没有机会变异为 null
。但是,在编译器不能保证流分析的其他情况下,这将是一个错误:
var nullableInt: Int? = ...
public fun foo() {
if (nullableInt != null) {
// Error: "Smart cast to 'kotlin.Int' is impossible, because 'nullableInt' is a mutable property that could have been changed by this time"
val nonNullableInt: Int = nullableInt
}
}
变量nullableInt
的生命周期不完全可见,可能从其他线程赋值,null
检查不能smart cast为非空值。有关解决方法,请参阅下面的 "Safe Calls" 主题。
另一种 smart cast 不能相信不会发生变异的情况是 val
属性 在具有自定义 getter 的对象上。在这种情况下,编译器看不到是什么改变了值,因此您将收到一条错误消息:
class MyThing {
val possibleXyz: Xyz?
get() { ... }
}
// now when referencing this class...
val thing = MyThing()
if (thing.possibleXyz != null) {
// error: "Kotlin: Smart cast to 'kotlin.Int' is impossible, because 'p.x' is a property that has open or custom getter"
thing.possiblyXyz.foo()
}
您可以使用let
来简化代码。 kotlin 作用域函数在 "num" 的上下文中引入了一个局部变量。无需声明临时变量 numVal
.
fun main(args: Array<String>) {
var num: Int? = null
// Stuff happens that might make num not null
...
num?.let{
doSomething(it)
}
}
它的工作原理与下面相同,但更简单、更清晰。
fun main(args: Array<String>) {
var num: Int? = null
// Stuff happens that might make num not null
...
val numVal: Int? = num
if (numVal != null) doSomething(numVal)
}
可以使用作用域函数 let 或 apply 以及 null 安全运算符 ?。
fragmentManager?.let{
viewPager.adapter = TasksPagerAdapter(it)
}
这样您就可以将可空类型传递给不可空类型参数
如果我在通过之前进行空检查,这可能吗?例如:
fun main(args: Array<String>) {
var num: Int? = null
// Stuff happens that might make num not null
...
if (num != null) doSomething(num)
}
fun doSomething(number: Int) {
...
}
我不明白为什么编译器不允许我传递可空值,即使我先检查它不为空。谁能解释一下?
注意:从编译器版本 1.0 beta 开始,相关代码按原样运行
编译器可以判断变量是否在检查和使用之间发生了变化,至少在这个问题中的局部变量以及其他一些情况下是这样。有关详细信息,请参阅
http://kotlinlang.org/docs/reference/null-safety.html#checking-for-null-keyword--in-conditions 说
The compiler tracks the information about the [null] check ... this only works where b is immutable (i.e. a local val or a member val which has a backing field and is not overridable), because otherwise it might happen that b changes to null after the check.
所以像这样的东西应该可以工作:
fun main(args: Array<String>) {
var num: Int? = null
// Stuff happens that might make num not null
...
val numVal: Int? = num
if (numVal != null) doSomething(numVal)
}
fun doSomething(number: Int) {
...
}
当然,重写 "stuff happens" 会更好,这样一开始就可以将 num
变成 val
。
在当前的 Kotlin(1.0 测试版或更新版本)中,您不再遇到此问题。你的代码会编译。 val
或 var
的局部变量可以安全地 Smart Cast 因为编译器可以确定该值是否可能已经发生变化(例如在另一个线程上)。
以下是
有关 null
检查和智能转换的更多信息
如果您使用 null
检查保护对可空类型的访问,编译器将 smart cast 语句主体中的值不可为空。有一些复杂的流程是不可能发生这种情况的,但对于常见情况来说效果很好。
val possibleXyz: Xyz? = ...
if (possibleXyz != null) {
// allowed to reference members:
possiblyXyz.foo()
// or also assign as non-nullable type:
val surelyXyz: Xyz = possibleXyz
}
或者,如果您执行 is
检查不可空类型:
if (possibleXyz is Xyz) {
// allowed to reference members:
possiblyXyz.foo()
}
对于同样安全转换的 'when' 表达式也是如此:
when (possibleXyz) {
null -> doSomething()
else -> possibleXyz.foo()
}
// or
when (possibleXyz) {
is Xyz -> possibleXyz.foo()
is Alpha -> possibleXyz.dominate()
is Fish -> possibleXyz.swim()
}
有些东西不允许 null
检查到 smart cast 以便以后使用变量。上面的示例使用了一个局部变量,该变量绝不会在应用程序的流程中发生变异,无论是 val
还是 var
,该变量都没有机会变异为 null
。但是,在编译器不能保证流分析的其他情况下,这将是一个错误:
var nullableInt: Int? = ...
public fun foo() {
if (nullableInt != null) {
// Error: "Smart cast to 'kotlin.Int' is impossible, because 'nullableInt' is a mutable property that could have been changed by this time"
val nonNullableInt: Int = nullableInt
}
}
变量nullableInt
的生命周期不完全可见,可能从其他线程赋值,null
检查不能smart cast为非空值。有关解决方法,请参阅下面的 "Safe Calls" 主题。
另一种 smart cast 不能相信不会发生变异的情况是 val
属性 在具有自定义 getter 的对象上。在这种情况下,编译器看不到是什么改变了值,因此您将收到一条错误消息:
class MyThing {
val possibleXyz: Xyz?
get() { ... }
}
// now when referencing this class...
val thing = MyThing()
if (thing.possibleXyz != null) {
// error: "Kotlin: Smart cast to 'kotlin.Int' is impossible, because 'p.x' is a property that has open or custom getter"
thing.possiblyXyz.foo()
}
您可以使用let
来简化代码。 kotlin 作用域函数在 "num" 的上下文中引入了一个局部变量。无需声明临时变量 numVal
.
fun main(args: Array<String>) {
var num: Int? = null
// Stuff happens that might make num not null
...
num?.let{
doSomething(it)
}
}
它的工作原理与下面相同,但更简单、更清晰。
fun main(args: Array<String>) {
var num: Int? = null
// Stuff happens that might make num not null
...
val numVal: Int? = num
if (numVal != null) doSomething(numVal)
}
可以使用作用域函数 let 或 apply 以及 null 安全运算符 ?。
fragmentManager?.let{
viewPager.adapter = TasksPagerAdapter(it)
}
这样您就可以将可空类型传递给不可空类型参数