美文网首页
高效的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——限制可变性

    限制可变性(Limit mutability) 只读属性 val 只读属性val可以改变,但是只读属性并没有提供修...

  • Kotlin学习笔记(五)集合

    1.kotlin中的集合 在kotlin中把集合拆分成只读的集合和可变性的集合 2.集合与可空性 可以包含为 nu...

  • Kotlin之美——DSL篇

    Kotlin 系列:Kotlin之美——高效篇Kotlin之美——DSL篇 Kotlin DSL 把 Kotlin...

  • Kotlin

    使用Kotlin高效地开发Android App(一) 使用Kotlin高效地开发Android App(二) 使...

  • Kotlin之美——高效篇

    Kotlin 系列:Kotlin之美——高效篇Kotlin之美——DSL篇 Kotlin 作为后起之秀,站在巨人们...

  • Kotlin入门四 集合

    1.目录 二、集合类型 Kotlin 中的集合按照可变性分类可以分为: 可变集合 不可变集合 按照类型分类可以分为...

  • Kotlin Weekly 中文周报 —— 102

    Kotlin 开发中文周报 使用 Kotlin 高效地开发 Android App(五)完结篇 (jianshu....

  • kotlin入门篇

    why kotlin kotlin引入现代语言的所有特性,而没有引入新的限制,它适合android原生开发 兼容性...

  • Rust内部可变性之RefCell

    背景 在Rust中,每个对象(变量)的可见性与可变性均受到所有权的限制,一个对象只能有一个所有者。这个限制对于内存...

  • 高效的Kotlin

    最近在看一本书——Effective Kotlin[https://leanpub.com/effectiveko...

网友评论

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

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