聪明的演员是不可能的,因为…是一个可变的财产,可能已经改变了这个时间

我正在努力获得一个类,它结合了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? = null var set : ReferenceOpenHashSet? = null var map : Reference2ReferenceOpenHashMap? = null fun isEmpty() : Boolean { return list === null && set === null && map === null } fun isScalar() : Boolean { if(list !== null && list.size == 1) { return true } } } 

不幸的是,它给了我比较错误

 list !== null && list.size == 1 

 Smart cast to 'ReferenceArrayList' is impossible, because 'list' is a mutable property that could have been changed by this time 

据我所知,这与multithreading的假设有关。 在Java中,如果期望multithreading,我会让函数synchronized 。 另外,如果我不写线程安全的话,我完全可以忽视这个。

我应该如何写Kotlin?

我看到这个解决方案https://stackoverflow.com/a/44596284/258483,但它期望MT,我不想。 如何避免智能铸造,如果它不能做到这一点?

UPDATE

问题是如何以相同的“程序”forms来做到这一点。 如何不使用智能铸造?

更新2

总而言之,就我所了解,根本不可能/合理地将variables与Kotlin中的null进行比较。 因为一旦你比较了它,下一次你应该用null这样的操作隐式地再次将它与null比较.? 你无法避免这一点。

如果你利用了null不能等于1 (或其他任何东西)的事实,你可以使这个检查非常简洁:

 fun isScalar() : Boolean = list?.size == 1 

当一个对list.size的null-safe调用返回null时,我们得到false因为1 != null 。 否则,无论什么价值size回报作出比较,那就像你所期望的那样。

通过使用空安全运算符( ?. ),您完全避免了一个聪明的演员。 Kotlin为我们提供了精明的代码,使代码更加清晰,这也是保护我们免受滥用的特性之一 。 Kotlin不会保护我们不受任何东西的限制(例如零分,例如你在评论中使用的例子)。 你的代码陷入了一个合理的情况下,聪明的铸造可能出错,所以Kotlin跳进来帮忙。

但是,如果你确定没有其他线程正在工作,那么是的,这个检查是“错误的”。 在这种情况下,你不需要警告。 通过kotlinlang.org上的这个线程判断 ,你不是唯一的!

您可以执行空检查,如果成功,则使用let访问variables的只读副本:

 fun isScalar() : Boolean { return list?.let { it.size == 1 } ?: false } 
  • 如果list为null,则整个letexpression式将计算为null ,并且将返回Elvis运算符( false )的右侧。
  • 如果list不为null,则调用let函数,并返回it.size == 1expression式的结果 – it指的是调用的对象(本例中为list )。 由于它使用了一个安全的调用 , it它将有一个不可为空的types,并且可以调用它的size