首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >kotlin自定义从mutableList获取不可变列表

kotlin自定义从mutableList获取不可变列表
EN

Stack Overflow用户
提问于 2018-06-02 01:53:29
回答 3查看 2.9K关注 0票数 1

我使用Google的Guava库为可变列表提供了一个自定义的getter方法,以返回一个不可接受的列表。然后在构造函数中访问这个可变列表。

代码语言:javascript
复制
data class mutableClass(val list: List<Foo>) {

    private val mutableList: MutableList<Foo>
        get() = ImmutableList.copyOf(field)

    init {
       mutableList = mutableListOf()
       list.forEach {
          mutableList.add(it.copy()) // Exception is thrown here.
          // It actually calls its getter method which is an immutable 
          // list, so when init this class, it throw exception                   
       }
    }
}

data class Foo {}

我把它反编译成Java,在初始化代码块中,它调用了mutableList的getter方法。有没有办法调用mutabbleList本身而不是getter方法?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-06-02 02:16:54

当然,它会调用getter (返回ImmutableList.copyOf(field))。

您可以在init块中简单地对新复制的可变列表进行mutableList赋值:

代码语言:javascript
复制
data class MutableClass(val list: List<Foo>) {

    private val mutableList: MutableList<Foo>
        get() = ImmutableList.copyOf(field)

    init {
        mutableList = list.map { it.copy() }.toMutableList()
    }
}

或者没有init

代码语言:javascript
复制
data class MutableClass(val list: List<Foo>) {

    private val mutableList: MutableList<Foo> = list.map { it.copy() }.toMutableList()
        get() = ImmutableList.copyOf(field)

}
票数 2
EN

Stack Overflow用户

发布于 2019-09-18 21:34:45

Kotlin stdlib选择了接口的不变性。这意味着,封装实现的接口决定了引用本身的可变性。

因此,使MutableList<T>成为List<T>的正确方法是将其装箱,如下所示:

代码语言:javascript
复制
val myMutableList = mutableListOf(1, 2, 3, 4)
val myImmutableList = myMutableList as List<Int>

这样,作为List<Int>中的myImmutableList引用,它将只公开来自List<Int>的成员,而不是那些仅由MutableList<Int>定义的成员,这些成员允许改变对象的状态,因此也就是列表。

然后,如果你真的想避免下面的问题(从上面的代码恢复),

代码语言:javascript
复制
val hackedList = myImmutableList as MutableList<Int>

..。对于您可以通过取消装箱访问可变实现的情况,您可能会选择以下解决方案:

代码语言:javascript
复制
class ImmutableList<T>(list: MutableList<T>) : List<T> by list

fun <T> MutableList<T>.toImmutable() = ImmutableList(this)

然后按如下方式使用它:

代码语言:javascript
复制
val myMutableList = mutableListOf(1, 2, 3, 4)
val myImmutableList = myMutableList.toImmutable()

因此,您将避免上面的问题。实际上,任何对从MutableList<T>.toImmutable()返回的值进行拆箱的尝试都将以TypeCastException结束,因为List<T>的实现不再是MutableList<T>。相反,它是一个ImmutableList<T>,它不会公开任何可能改变对象的方法。

与@Lucas方法不同,这种方法不会浪费时间复制元素,因为您将依赖Kotlin中的by关键字,它允许您通过已存在的实现来实现接口。也就是说,您将传递给ImmutableList<T>的构造函数的MutableList<T>

票数 0
EN

Stack Overflow用户

发布于 2021-04-19 14:48:48

对我来说,使用var而不是val字段和一个私有setter通常效果最好

代码语言:javascript
复制
class Order

class Something() {

    var orders: List<Order> = listOf()
        private set

    fun addOrder(order: Order) {
        orders = orders
            .toMutableList()
            .apply { add(order) }
    }
}

这将它公开为不可变的,并且只需要一个字段。我们付出的代价是在添加元素时创建一个新集合的开销。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50648717

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档