我正在尝试获得一个类,它将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
}
}
}
不幸的是它在比较中给了我错误
list !== null && list.size == 1
说
Smart cast to 'ReferenceArrayList<M>' is impossible, because 'list' is a mutable property that could have been changed by this time
据我所知,这与多线程假设有关。在Java中,如果期望多线程,我会创建函数synchronized
。此外,如果我不编写线程安全的话,我可以完全忽略这一点。
我应该怎么写Kotlin?
我看到了这个解决方案https://stackoverflow.com/a/44596284/258483,但它预计MT,我不想这样做。如果做不到,如何避免智能铸造呢?
更新
问题是如何以相同的“程序”形式执行此操作。如何不使用智能铸造?
更新2
总结一下,据我所知,在Kotlin中明确地将变量与null
进行比较是不可能/合理的。因为一旦你比较它,下次你可以用null
这样的操作隐式地将它与.?
进行比较,你无法避免这种情况。
答案 0 :(得分:2)
您可以执行空检查,如果成功,则使用let
访问变量的只读副本:
fun isScalar() : Boolean {
return list?.let { it.size == 1 } ?: false
}
list
为空,则整个let
表达式将评估为null
,并且将返回Elvis运算符(false
)的右侧。list
不为null,则调用let
函数,并返回it.size == 1
表达式的结果 - it
引用{{1}的对象调用(在这种情况下为let
)。由于它与safe call一起使用,因此list
将具有非可空类型,并且可以在其上调用it
。答案 1 :(得分:2)
如果你利用null
不能等于1
(或其他任何东西,真的)的事实,你可以非常简洁地进行检查:
fun isScalar() : Boolean =
list?.size == 1
当对list.size
的空安全调用返回null时,我们得到false
因为1 != null
。否则,将进行任何值size
返回的比较,并且按预期工作。
通过使用null安全操作符(?.
),您完全避免使用智能转换。 Kotlin为我们提供了智能模型以使代码更清晰,这是它保护我们免受滥用功能的方法之一。 Kotlin不会保护我们免受任何事情的影响(例如,除以零,你在评论中使用的例子)。你的代码陷入了一个合理的情况,智能铸造可能出错,所以Kotlin跳槽帮忙。
但是,如果你完全确定没有其他线程可以工作,那么是的,这个检查是“错误的”。在这种情况下你不需要警告。从this thread on kotlinlang.org来看,你不是唯一的一个!
答案 2 :(得分:2)
在给定的行中我遇到了同样的问题
sliderView.setSliderAdapter(adapter!!)
sliderView.setIndicatorAnimation(IndicatorAnimationType.WORM)
最后,通过添加!!解决了错误
sliderView!!.setSliderAdapter(adapter!!)
sliderView!!.setIndicatorAnimation(IndicatorAnimationType.WORM)