【问题标题】:Kotlin's List missing "add", "remove", Map missing "put", etc?Kotlin 的列表缺少“添加”、“删除”、地图缺少“放置”等?
【发布时间】:2016-10-21 03:53:13
【问题描述】:

在 Java 中,我们可以执行以下操作

public class TempClass {
    List<Integer> myList = null;
    void doSomething() {
        myList = new ArrayList<>();
        myList.add(10);
        myList.remove(10);
    }
}

但是如果我们像下面这样直接重写成Kotlin

class TempClass {
    var myList: List<Int>? = null
    fun doSomething() {
        myList = ArrayList<Int>()
        myList!!.add(10)
        myList!!.remove(10)
    }
}

我收到了从我的列表中找不到addremove 函数的错误

我解决了将它转换为 ArrayList 的工作,但是需要转换它很奇怪,而在 Java 中则不需要转换。这违背了拥有抽象类 List 的目的

class TempClass {
    var myList: List<Int>? = null
    fun doSomething() {
        myList = ArrayList<Int>()
        (myList!! as ArrayList).add(10)
        (myList!! as ArrayList).remove(10)
    }
}

有没有办法让我使用 List 但不需要强制转换,就像在 Java 中可以做的那样?

【问题讨论】:

  • 只是评论为什么你不能做myList = null,然后在没有!!的情况下添加。您可以通过在属性前面使用 lateinit 关键字来克服这个问题,如下所示:lateinit var myList: List&lt;Int&gt; 这样您就不需要立即初始化列表,但您向编译器保证您将在使用列表之前对其进行初始化第一次。这是一个更顺畅的解决方案,但它让您作为开发人员承担责任。

标签: collections kotlin


【解决方案1】:

显然,Kotlin 的默认 List 是不可变的。 要拥有一个可以更改的列表,应该使用 MutableList,如下所示

class TempClass {
    var myList: MutableList<Int>? = null
    fun doSomething() {
        myList = ArrayList<Int>()
        myList!!.add(10)
        myList!!.remove(10)
    }
}

更新 尽管如此,不建议使用 MutableList,除非您确实想要更改列表。请参阅https://hackernoon.com/read-only-collection-in-kotlin-leads-to-better-coding-40cdfa4c6359,了解只读集合如何提供更好的编码。

【讨论】:

  • 您使用MutableList 是正确的,但是使用null 对其进行初始化将不起作用。在 MutableList&lt;Int&gt; 类型的可空接收器上只允许安全或非空断言调用。
  • 它适用于我,没有发现错误。我不需要初始化它,除非当我需要它时doSomething
  • @Elye 我知道这是一个旧的答案和问题,但是使用lateinit 而不是使列表可以为空是解决此问题的正确方法。不记得 lateinit 是否是从 Kotlin 开始添加的,但这绝对是当今使用它的解决方案:-)
【解决方案2】:

与许多语言不同,Kotlin 区分可变集合和不可变集合(列表、集合、映射等)。精确控制何时可以编辑集合对于消除错误和设计良好的 API 很有用。

https://kotlinlang.org/docs/reference/collections.html

您需要使用MutableList 列表。

class TempClass {
    var myList: MutableList<Int> = mutableListOf<Int>()
    fun doSomething() {
        // myList = ArrayList<Int>() // initializer is redundant
        myList.add(10)
        myList.remove(10)
    }
}

MutableList&lt;Int&gt; = arrayListOf() 也应该可以工作。

【讨论】:

  • 答案写得很好。尽管下面有我的答案,但我还是选择了你的答案:)
  • 如果立即初始化列表,则无需将其设为可空。我编辑了你的答案。
【解决方案3】:

在不可变数据的概念中,也许这是一种更好的方式:

class TempClass {
    val list: List<Int> by lazy {
        listOf<Int>()
    }
    fun doSomething() {
        list += 10
        list -= 10
    }
}

【讨论】:

    【解决方案4】:

    https://kotlinlang.org/docs/reference/collections.html

    根据上面的链接 List 在 Kotlin 中是不可变的。 但是这会起作用:

    var list2 = ArrayList<String>()
    list2.removeAt(1)
    

    【讨论】:

    【解决方案5】:

    在 Kotlin 中以不同方式定义 List 集合:

    • 具有不可变(只读)列表的不可变变量:

      val users: List<User> = listOf( User("Tom", 32), User("John", 64) )
      


    • 带有可变列表的不可变变量:

      val users: MutableList<User> = mutableListOf( User("Tom", 32), User("John", 64) )
      

      或者没有初始值 - 空列表并且没有明确的变量类型:

      val users = mutableListOf<User>()
      //or
      val users = ArrayList<User>()
      
      • 您可以将项目添加到列表中:
        • users.add(anohterUser)
        • users += anotherUser(在后台是users.add(anohterUser)


    • 具有不可变列表的可变变量:

      var users: List<User> = listOf( User("Tom", 32), User("John", 64) )
      

      或者没有初始值 - 空列表并且没有明确的变量类型:

      var users = emptyList<User>()
      
      • 注意:您可以将*项添加到列表中:
        • users += anotherUser - *它创建新的 ArrayList 并将其分配给 users


    • 带有可变列表的可变变量:

      var users: MutableList<User> = mutableListOf( User("Tom", 32), User("John", 64) )
      

      或者没有初始值 - 空列表并且没有明确的变量类型:

      var users = emptyList<User>().toMutableList()
      //or
      var users = ArrayList<User>()
      
      • 注意:您可以将项目添加到列表中:
        • users.add(anohterUser)
        • 但不使用users += anotherUser

          错误:Kotlin:赋值运算符不明确:
          public operator fun Collection.plus(element: String):在 kotlin.collections 中定义的列表
          @InlineOnly public inline operator fun MutableCollection.plusAssign(element: String): Unit定义在kotlin.collections中


    也可以看看: https://kotlinlang.org/docs/reference/collections.html

    【讨论】:

      【解决方案6】:

      同意上述使用 MutableList 的所有答案,但您也可以从 List 中添加/删除并获取新列表,如下所示。

      val newListWithElement = existingList + listOf(element)
      val newListMinusElement = existingList - listOf(element)
      

      或者

      val newListWithElement = existingList.plus(element)
      val newListMinusElement = existingList.minus(element)
      

      【讨论】:

        【解决方案7】:

        listimmutable by Default,您可以改用 ArrayList。像这样:

         val orders = arrayListOf<String>()
        

        然后你可以add/delete来自下面的项目:

        orders.add("Item 1")
        orders.add("Item 2")
        

        默认ArrayListmutable,所以你可以对其进行操作。

        【讨论】:

          【解决方案8】:

          在 Kotlin 中,您必须使用 MutableListArrayList

          让我们看看 MutableList 的方法是如何工作的:

          var listNumbers: MutableList<Int> = mutableListOf(10, 15, 20)
          // Result: 10, 15, 20
          
          listNumbers.add(1000)
          // Result: 10, 15, 20, 1000
          
          listNumbers.add(1, 250)
          // Result: 10, 250, 15, 20, 1000
          
          listNumbers.removeAt(0)
          // Result: 250, 15, 20, 1000
          
          listNumbers.remove(20)
          // Result: 250, 15, 1000
          
          for (i in listNumbers) { 
              println(i) 
          }
          

          让我们看看ArrayList的方法是如何工作的:

          var arrayNumbers: ArrayList<Int> = arrayListOf(1, 2, 3, 4, 5)
          // Result: 1, 2, 3, 4, 5
          
          arrayNumbers.add(20)
          // Result: 1, 2, 3, 4, 5, 20
          
          arrayNumbers.remove(1)
          // Result: 2, 3, 4, 5, 20
          
          arrayNumbers.clear()
          // Result: Empty
          
          for (j in arrayNumbers) { 
              println(j) 
          }
          

          【讨论】:

            【解决方案9】:

            更新:从 Kotlin 1.3.70 开始,下面的确切 buildList 函数是标准库中的 available 作为实验函数,以及它的类似函数 buildSetbuildMap .见https://blog.jetbrains.com/kotlin/2020/03/kotlin-1-3-70-released/

            限制构建器的可变性

            这里的最佳答案正确地说明了 Kotlin 中只读 List(注意:it's read-only, not "immutable")和 MutableList 之间的区别。

            一般来说,应该努力使用只读列表,但是,可变性在构造时仍然很有用,尤其是在处理具有非功能接口的第三方库时。对于替代构造技术不可用的情况,例如直接使用listOf,或应用像foldreduce 这样的函数构造,如下所示的简单“构建器函数”构造可以很好地生成只读列表从一个临时可变的:

            val readonlyList = mutableListOf<...>().apply {
              // manipulate your list here using whatever logic you need
              // the `apply` function sets `this` to the `MutableList`
              add(foo1)
              addAll(foos)
              // etc.
            }.toList()
            

            这可以很好地封装成一个可重用的内联实用函数:

            inline fun <T> buildList(block: MutableList<T>.() -> Unit) = 
              mutableListOf<T>().apply(block).toList()
            

            可以这样调用:

            val readonlyList = buildList<String> {
              add("foo")
              add("bar")
            }
            

            现在,所有的可变性都被隔离到一个用于构建只读列表的块范围内,您的其余代码使用从构建器输出的只读列表。

            【讨论】:

            • 感谢并在 apply 方法中很好地处理业务逻辑,甚至在 .appy 中使用了 anotherList.ForEach {add(foo)}{}
            【解决方案10】:

            你可以像这样新建一个。

            var list1 = ArrayList<Int>()
            var list2  = list1.toMutableList()
            list2.add(item)
            

            现在可以使用list2了,谢谢。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-02-19
              • 1970-01-01
              • 1970-01-01
              • 2018-10-01
              • 1970-01-01
              相关资源
              最近更新 更多