Kotlin `?.let` 是线程安全的吗?
Posted
技术标签:
【中文标题】Kotlin `?.let` 是线程安全的吗?【英文标题】:Is Kotlin `?.let` thread-safe? 【发布时间】:2019-12-10 22:42:06 【问题描述】:Kotlin ?.let
线程安全吗?
假设a
变量可以在不同的线程中更改。
使用a?.let /* */
线程安全吗?如果它等于if (a != null) block()
,会不会在if
中不为空而在block
中已经为空?
【问题讨论】:
我想如果让这个操作线程安全就太过分了a
在块执行时可以为空,但it
不能。 IE。相当于val copy = a; if (copy != null) block(copy)
@4ntoine 当 Kotlin 编译器智能地将可空类型转换为不可空类型时,您可以确定它确实是非空的。如果代码不是线程安全的,编译器会给你一个编译器错误(就像你这样做if (a != null) a.someFunction()
)
它会给你的编译器错误是这样的(如果a
是Int?
类型):Smart cast to 'Int' is impossible, because 'a' is a mutable property that could have been changed by this time
【参考方案1】:
a?.let block()
确实等价于if (a != null) block()
。
这也意味着如果a
是一个可变变量,那么:
a
可能会在空检查后重新分配,并在执行block()
时保持null
值;
所有与并发相关的效果都有效,如果a
在线程之间共享以避免竞争条件,则需要正确同步;
但是,由于let ...
实际上将其接收者作为单个参数传递给它所接受的函数,它可以用于捕获a
的值并在 lambda 中使用它,而不是在 @ 中再次访问该属性987654330@。例如:
a?.let notNullA -> block(notNullA)
// with implicit parameter `it`, this is equivalent to:
a?.let block(it)
这里,作为参数传递给 lambda 的 a
的值保证与检查为 null 的值相同。但是,在 block()
中再次观察 a
可能会返回 null 或不同的值,并且观察给定实例的可变状态也应该正确同步。
【讨论】:
…而后一种情况是线程安全的。 (从某种意义上说,let
参数始终与?.
检查的值相同,因此永远不能为空。但是,如果在此期间a
发生了变化,则不会反映这一点。 )
@gidds 这很有趣。有证据吗?
我认为它遵循 ?.
运算符的工作方式:它从表达式的左侧获取值(这可能意味着调用 getter 或其他),检查它是否为空,如果不是,对该值调用以下方法。在这种情况下,let()
然后将该值作为参数传递给函数。因此,在任何时候都没有机会获取不同的值。当然,如果值是一个可变对象,那么它的状态可以改变。但它必须是同一个对象。
@gidds,谢谢,我已经在答案中添加了关于它的评论。实际上,?.
只会访问该变量一次,如果返回值不为空,则调用该函数。
@AlexeyRomanov 我的陈述假定block
是无参数的,所以我会说它成立但不能解释?.let ...
的整个语义。谢谢你的评论!以上是关于Kotlin `?.let` 是线程安全的吗?的主要内容,如果未能解决你的问题,请参考以下文章