Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/regex/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Kotlin和不可变集合?_Kotlin - Fatal编程技术网

Kotlin和不可变集合?

Kotlin和不可变集合?,kotlin,Kotlin,我正在学习Kotlin,看来我可能想在明年内把它作为我的主要语言。然而,我不断得到相互矛盾的研究,Kotlin有或没有不可变的集合,我试图弄清楚我是否需要使用谷歌番石榴 有人能给我一些指导吗?默认情况下是否使用不可变集合?哪些运算符返回可变集合或不可变集合?如果没有,是否有实施计划?标准库中的Kotlin是只读的: interface List<out E> : Collection<E> (source) 支持添加和删除的元素的常规有序集合 删除元素 参数 E-列表中

我正在学习Kotlin,看来我可能想在明年内把它作为我的主要语言。然而,我不断得到相互矛盾的研究,Kotlin有或没有不可变的集合,我试图弄清楚我是否需要使用谷歌番石榴

有人能给我一些指导吗?默认情况下是否使用不可变集合?哪些运算符返回可变集合或不可变集合?如果没有,是否有实施计划?

标准库中的Kotlin是只读的:

interface List<out E> : Collection<E> (source)
支持添加和删除的元素的常规有序集合 删除元素

参数
E-列表中包含的元素类型

因此,Kotlin通过其接口强制执行只读行为,而不是像默认Java实现那样在运行时抛出异常


类似地,还有
MutableCollection
MutableIterable
MutableIterator
MutableListIterator
MutableMap
,和
MutableSet
,请参见文档。

这令人困惑,但有三种,而不是两种类型的不变性:

  • 可变-您应该更改集合(Kotlin的
    可变列表
  • 只读-您不应该更改它(Kotlin的
    列表
    ),但可能会更改某些内容(转换为可变的,或从Java更改)
  • 不可变-没有人可以更改它(Guavas的不可变集合)
  • 因此,在案例(2)
    List
    只是一个没有变异方法的接口,但是如果将实例强制转换为
    MutableList
    ,则可以更改该实例

    使用番石榴(案例(3))时,任何人都可以安全地更改收藏,即使使用石膏或其他线


    Kotlin选择只读是为了直接使用Java集合,因此在使用Java集合时没有开销或转换。

    Kotlin 1.0在标准库中没有不可变的集合。但是,它确实具有只读和可变接口。并且没有任何东西阻止您使用第三方不可变集合库

    Kotlin接口中的方法“仅支持对列表的只读访问”,而其接口中的方法支持“添加和删除元素”。然而,这两个都只是接口

    Kotlin的
    List
    接口在编译时强制执行只读访问,而不是将此类检查延迟到运行时,如“返回指定列表的不可修改视图…[其中]尝试修改返回的列表…会导致错误”。它不强制执行不可变性。

    考虑以下Kotlin代码:

    import com.google.common.collect.ImmutableList
    import kotlin.test.assertEquals
    import kotlin.test.assertFailsWith
    
    fun main(args: Array<String>) {
        val readOnlyList: List<Int> = arrayListOf(1, 2, 3)
        val mutableList: MutableList<Int> = readOnlyList as MutableList<Int>
        val immutableList: ImmutableList<Int> = ImmutableList.copyOf(readOnlyList)
    
        assertEquals(readOnlyList, mutableList)
        assertEquals(mutableList, immutableList)
    
        // readOnlyList.add(4) // Kotlin: Unresolved reference: add
        mutableList.add(4)
        assertFailsWith(UnsupportedOperationException::class) { immutableList.add(4) }
    
        assertEquals(readOnlyList, mutableList)
        assertEquals(mutableList, immutableList)
    }
    
    import com.google.common.collect.ImmutableList
    导入kotlin.test.assertEquals
    导入kotlin.test.assertFailsWith
    趣味主线(args:Array){
    val readOnlyList:List=arrayListOf(1,2,3)
    val mutableList:mutableList=readOnlyList作为mutableList
    val immutableList:immutableList=immutableList.copyOf(readOnlyList)
    assertEquals(只读列表、可变列表)
    assertEquals(可变列表、不可变列表)
    //readOnlyList.add(4)//Kotlin:未解析的引用:add
    可变列表。添加(4)
    assertFailsWith(UnsupportedOperationException::class){immutableList.add(4)}
    assertEquals(只读列表、可变列表)
    assertEquals(可变列表、不可变列表)
    }
    
    请注意,
    readOnlyList
    是一个
    列表
    ,诸如
    add
    之类的方法无法解析(也不会编译),
    mutableList
    可以自然变异,而
    immutableList
    上的
    add
    也可以在编译时解析,但在运行时抛出异常

    以上所有断言都通过了,但最后一个断言除外,它导致线程“main”java.lang中出现
    异常。断言错误:预期,实际。
    即,我们成功地变异了只读
    列表

    请注意,使用
    listOf(…)
    而不是
    arrayListOf(…)
    返回一个有效的不可变列表,因为您无法将其强制转换为任何可变列表类型。但是,对变量使用
    list
    接口并不会阻止将
    MutableList
    分配给它(
    MutableList
    扩展了
    List

    最后,请注意,Kotlin(以及Java)中的接口不能强制执行不变性,因为它“不能存储状态”(请参阅)。因此,如果您想要一个不可变的集合,您需要使用类似于Google Guava提供的集合



    另请参见

    正如您在其他答案中看到的,Kotlin具有可变集合的只读接口,允许您通过只读镜头查看集合。但是可以通过强制转换绕过集合或从Java操作集合。但是在协作Kotlin代码中,大多数使用不需要真正不变的集合,如果您的团队ds强制转换为集合的可变形式,那么您可能不需要完全不变的集合

    Kotlin集合既允许更改时复制突变,也允许延迟突变。因此,为了回答您的部分问题,像
    过滤器
    映射
    平面映射
    ,操作符
    +
    -
    都会在对非延迟集合使用时创建副本。当在
    序列
    上使用时,它们会修改这些值在被访问时作为集合,并且继续是惰性的(导致另一个
    序列
    )。虽然对于
    序列
    ,调用任何诸如
    toList
    toSet
    toMap
    之类的命令都会生成最终副本。按照命名约定,几乎任何以
    to
    开头的命令都会生成副本

    换句话说,大多数操作符返回的类型与开始时相同,如果该类型为“readonly”,则您将收到一个副本。如果该类型为lazy,则您将收到一个副本
    import com.google.common.collect.ImmutableList
    import kotlin.test.assertEquals
    import kotlin.test.assertFailsWith
    
    fun main(args: Array<String>) {
        val readOnlyList: List<Int> = arrayListOf(1, 2, 3)
        val mutableList: MutableList<Int> = readOnlyList as MutableList<Int>
        val immutableList: ImmutableList<Int> = ImmutableList.copyOf(readOnlyList)
    
        assertEquals(readOnlyList, mutableList)
        assertEquals(mutableList, immutableList)
    
        // readOnlyList.add(4) // Kotlin: Unresolved reference: add
        mutableList.add(4)
        assertFailsWith(UnsupportedOperationException::class) { immutableList.add(4) }
    
        assertEquals(readOnlyList, mutableList)
        assertEquals(mutableList, immutableList)
    }
    
    /**
     * Wraps a List with a lightweight delegating class that prevents casting back to mutable type
     */
    open class ReadOnlyList <T>(protected val delegate: List<T>) : List<T> by delegate, ReadOnly, Serializable {
        companion object {
            @JvmField val serialVersionUID = 1L
        }
    
        override fun iterator(): Iterator<T> {
            return delegate.iterator().asReadOnly()
        }
    
        override fun listIterator(): ListIterator<T> {
            return delegate.listIterator().asReadOnly()
        }
    
        override fun listIterator(index: Int): ListIterator<T> {
            return delegate.listIterator(index).asReadOnly()
        }
    
        override fun subList(fromIndex: Int, toIndex: Int): List<T> {
            return delegate.subList(fromIndex, toIndex).asReadOnly()
        }
    
        override fun toString(): String {
            return "ReadOnly: ${super.toString()}"
        }
    
        override fun equals(other: Any?): Boolean {
            return delegate.equals(other)
        }
    
        override fun hashCode(): Int {
            return delegate.hashCode()
        }
    }
    
    /**
     * Wraps the List with a lightweight delegating class that prevents casting back to mutable type,
     * specializing for the case of the RandomAccess marker interface being retained if it was there originally
     */
    fun <T> List<T>.asReadOnly(): List<T> {
        return this.whenNotAlreadyReadOnly {
            when (it) {
                is RandomAccess -> ReadOnlyRandomAccessList(it)
                else -> ReadOnlyList(it)
            }
        }
    }
    
    /**
     * Copies the List and then wraps with a lightweight delegating class that prevents casting back to mutable type,
     * specializing for the case of the RandomAccess marker interface being retained if it was there originally
     */
    @Suppress("UNCHECKED_CAST")
    fun <T> List<T>.toImmutable(): List<T> {
        val copy = when (this) {
            is RandomAccess -> ArrayList<T>(this)
            else -> this.toList()
        }
        return when (copy) {
            is RandomAccess ->  ReadOnlyRandomAccessList(copy)
            else -> ReadOnlyList(copy)
        }
    }