Multithreading 聪明的演员是不可能的,因为。。。是此时可能已更改的可变属性

Multithreading 聪明的演员是不可能的,因为。。。是此时可能已更改的可变属性,multithreading,casting,kotlin,Multithreading,Casting,Kotlin,我正在尝试获取一个类,它在Kotlin中结合了列表、集合和映射。我希望编写isScalar函数,如果对象只包含一个元素并已写入,则该函数应返回true import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap import it.unimi.dsi.fastutil.objects.ReferenceArrayList import it.unimi.dsi.fastutil.objects.ReferenceOpen

我正在尝试获取一个类,它在
Kotlin
中结合了列表、集合和映射。我希望编写
isScalar
函数,如果对象只包含一个元素并已写入,则该函数应返回
true

import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap
import it.unimi.dsi.fastutil.objects.ReferenceArrayList
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet

class Args {

    var list : ReferenceArrayList<M>? = null

    var set : ReferenceOpenHashSet<M>? = null

    var map : Reference2ReferenceOpenHashMap<M, M>? = null

    fun isEmpty() : Boolean {
        return list === null && set === null && map === null
    }

    fun isScalar() : Boolean {
        if(list !== null && list.size == 1) {
            return true
        }
    }

}

Smart cast to 'ReferenceArrayList<M>' is impossible, because 'list' is a mutable property that could have been changed by this time
智能转换为“ReferenceArrayList”是不可能的,因为“list”是一个可变属性,此时可能已更改
据我所知,这与多线程假设有关。在Java中,如果希望使用多线程,我将使函数
同步。而且,如果我写的不是线程安全的,我完全可以忽略这一点

我应该如何用Kotlin书写

我看到了这个解决方案,但它需要MT,我不想这样。如果智能铸造做不到,如何避免智能铸造

更新

问题是如何以同样的“程序”形式做到这一点。如何不使用智能铸造

更新2


总之,据我所知,在Kotlin中显式地将变量与
null
进行比较是不可能/不合理的。因为一旦你比较了它,下一次你应该再次用类似
这样的操作隐式地将它与
null进行比较,你无法避免这一点。

你可以执行null检查,如果检查成功,用以下命令访问变量的只读副本:

  • 如果
    list
    为null,则整个
    let
    表达式将计算为
    null
    ,并返回Elvis运算符的右侧(
    false
  • 如果
    list
    不为null,则调用
    let
    函数,并返回
    it.size==1
    表达式的结果-
    it
    引用调用
    let
    的对象(
    list
    )。由于它与一起使用,因此此
    it
    将具有不可为空的类型,并且可以对其调用
    size

如果您利用了
null
不能等于
1
(或者其他任何事实),您可以使此检查非常简洁:

fun isScalar() : Boolean =
    list?.size == 1
当对
list.size
的空安全调用返回空值时,我们得到
false
,因为
1!=空
。否则,将对
size
返回的任何值进行比较,结果与您预期的一样

通过使用空安全运算符(
?。
),您完全避免了智能强制转换。Kotlin为我们提供了智能强制转换,使代码更干净,这是它保护我们不被滥用该功能的方法之一。Kotlin不会保护我们免受一切伤害(例如,你在评论中使用的除法为零)。你的代码陷入了一个合理的情况,即智能铸造可能出错,因此Kotlin跳出来帮忙


但是,如果您绝对确定没有其他线程在工作,那么是的,此检查是“错误的”。在那种情况下你不需要警告。从我看来,你不是唯一一个

我在给定的行中遇到了相同的问题

 sliderView.setSliderAdapter(adapter!!)
 sliderView.setIndicatorAnimation(IndicatorAnimationType.WORM)
最后,通过添加

 sliderView!!.setSliderAdapter(adapter!!)
 sliderView!!.setIndicatorAnimation(IndicatorAnimationType.WORM)

您看到的解决方案并不是“期望机器翻译”,它解释了Kotlin的静态分析为什么会如此工作<代码>如果智能铸造无法实现,如何避免智能铸造?
——不请求智能铸造。您的
list.size==1
请求一个智能强制转换,Kotlin拒绝了。使方法
同步
几乎不足以从另一个线程更新实例变量。事实上,你无法阻止它。@MarkoTopolnik那么如何不请求智能铸造呢?很难找到你到底需要帮助的地方。你的
列表
是一个可为空的类型,你不能仅仅取消引用它。你所要做的就是将一个实例变量加载到一个局部变量中。是的,我知道有
操作符,但我想了解,如何分解你所说的“如何分解”是什么意思?我不明白你的意思。无法关闭另一个线程可能进入并更改
列表
含义的检查,因此您必须通过不请求安全强制转换来解决此问题。否。没有办法把它关掉。但是,两个答案(me和@zsmb13)中的代码都是idomatic Kotlin。您应该在Kotlin创建者处解决这些问题。他们做出了一些他们认为有用的设计选择。对我来说,零安全是很好的。对你来说,不是。这不是争论的地方,也不是要求Kotlin用户以其创建者的名义回答的地方。空安全性与您想要命名的任何其他静态分析没有区别。它们都遵循严格的形式规则,不可能是完整的,即没有误报和误报。这在理论上是不可能的。此外,没有静态类型的语言允许您在任何时候禁用任何正式规则。总有一些规则是“必须”的,设计师很难在安全严格和危险宽松之间找到正确的平衡。
 sliderView.setSliderAdapter(adapter!!)
 sliderView.setIndicatorAnimation(IndicatorAnimationType.WORM)
 sliderView!!.setSliderAdapter(adapter!!)
 sliderView!!.setIndicatorAnimation(IndicatorAnimationType.WORM)