美文网首页
高效的Kotlin——限制可变性

高效的Kotlin——限制可变性

作者: 珞泽珈群 | 来源:发表于2021-02-10 18:06 被阅读0次

    限制可变性(Limit mutability)

    只读属性 val

    只读属性val可以改变,但是只读属性并没有提供修改的切入点,而修改切入点才是引起同步或者其他问题的主要原因。
    尽管val并不意味着“不可变”,例如我们可以通过自定义getter或者属性代理的方式定义val属性,这的确给了我们更多改变属性值的自由,但是在没有这些需求时,我们应该更倾向于使用final properties,Kotlin对其有更好的支持,例如smart cast:

    val name: String? = "Márton"
    val surname: String = "Braun"
    val fullName: String?
        get() = name?.let { "$it $surname" }
    val fullName2: String? = name?.let { "$it $surname" }
    fun main() {
        if (fullName != null) {
            println(fullName.length) // ERROR: Smart cast impossible
        }
        if (fullName2 != null) {
            println(fullName2.length) // Márton Braun
        }
    }
    

    区分只读、可变集合

    Kotlin支持只读集合(read-only collections),Kotlin的只读集合是通过集合类的继承层次结构上的“有意”设计而达成的,具体说来就是,把集合类分为可变集合类和只读集合类,所有的可变集合类都继承自相应的只读集合类。

    只读集合也不一定是不可变的,并且在底层实现上它们往往还真的就是可变集合,只是这些具体的实现被封装在只读接口之下,所以我们不能“轻易地”修改只读集合。例如,Iterable<T>.map, Iterable<T>.filter就是返回的ArrayList,但是通过只读接口List进行了屏蔽:

    public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
        val destination = ArrayList<R>(collectionSizeOrDefault(10)); transform)
        for (item in this)
            destination.add(transform(item))
        return destination
    }
    

    把只读集合设计成只读的而不是不可变的,给了我们更多的灵活性。在底层实现上,只要求具体的实现满足只读集合的接口即可,这样可以使用平台特定(platform-specific)的集合来实现Kotlin的只读集合(别忘了,Kotlin可是跨平台的语言)。
    但是,希望Kotlin提供真正的不可变集合的呼声一直是络绎不绝,Kotlin也听到了大家的呼声,在kotlinx中提供了相应实现,具体参见kotlinx.collections.immutable,其中提供了不可变集合(Immutable collections)和持久化集合(Persistent collections)。

    总结

    我们应该限制可变性并且尽可能使用“不可变”对象,Kotlin提供了很多相关的工具,我们应该善于使用它们来限制修改切入点(mutation points):

    1. 更多地使用val而不是var
    2. 更多地使用不可变属性。
    3. 更多地使用不可变类/对象(data class)。
    4. 如果需要修改一个对象的属性,考虑使用data class并且使用copy
    5. 当需要持有某种状态时,更多地使用只读集合而不是可变集合。
    6. 审慎地提供修改切入点,不要提供不必要的修改切入点。
    7. 不要对外暴露可变对象(mutable objects)。

    以上规则当然会有例外,例如,我们可能会想使用可变对象来提高效率,当性能成为瓶颈的时候,的确可以考虑这么做,但是你应该知道,可变性意味着在多线程时需要格外的小心。使用可变对象从状态修改的角度看的确可以提升效率,但是如果叠加由此引发的多线程锁的开销,可变对象是否真的能提升效率就是一件值得考虑的事情了。总之,我们应该限制可变性。


    从Immutability这一点其实可以看出编程语言的演进和软件工程的进化。Kotlin是“现代语言”中,选择拥抱Immutability的。

    从设计上看,可变和不可变属性是平等的(varval等长且很相似),甚至对于集合而言还更偏向于不可变集合(List vs MutableList),这些都是有意为之。相较而言,Java的可变和不可变就不是平等的(final vs 没有final),你或许会说Java更好啊,多个关键字更加的明确,但是扪心自问,是不是因为多个关键字你反而用的少得多。这不仅仅是个关键字的差别,表象背后体现的是编程哲学的不同。
    更多内容可以查看这篇文章Immutability we can afford,作者Kotlin Leader。

    Immutability is a luxury of programming, making software more comfortable and less error-prone to write in many important cases. Immutability is becoming more popular in software development because we became so rich in machine resources that we can afford it now.

    相关文章

      网友评论

          本文标题:高效的Kotlin——限制可变性

          本文链接:https://www.haomeiwen.com/subject/iiekxltx.html