В списке Котлина отсутствуют «добавить», «удалить», на карте отсутствует «положить» и т. Д.?

198

В Java мы могли бы сделать следующее

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

Но если мы перепишем его непосредственно в Котлин, как показано ниже

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

Я получил ошибку не найдя addи removeфункции из моего списка

Я работаю вокруг приведения его к 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?

Elye
источник
1
Просто комментарий о том, почему вы не можете сделать, myList = nullа затем добавить вызов без !!. Вы можете преодолеть это, используя lateinitключевое слово перед своим свойством, вот так: lateinit var myList: List<Int>таким образом вам не нужно будет инициализировать список немедленно, но вы гарантируете компилятору, что инициализируете его перед первым использованием списка. Это более плавное решение, но оно возлагает на вас ответственность как разработчика.
Дарвинд

Ответы:

352

В отличие от многих языков, 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<Int> = arrayListOf() также должен работать.

Фульвио
источник
4
Хороший и хорошо написанный ответ. Я выбираю ваш ответ как модель, несмотря на то, что у меня ниже :)
Elye
6
Вам не нужно делать список обнуляемым, если вы инициализируете его немедленно. Я отредактировал твой ответ.
Кирилл Рахман
37

Определение коллекции списков в Kotlin различными способами:

  • Неизменяемая переменная с неизменным (только для чтения) списком:

    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: неоднозначность операторов присваивания:
        открытый оператор fun Collection.plus (элемент: String): список определен в kotlin.collections
        @InlineOnly открытый встроенный оператор fun MutableCollection.plusAssign (element: String): модуль, определенный в kotlin.collections


см. также: https://kotlinlang.org/docs/reference/collections.html

Lukas
источник
9

Согласитесь со всеми приведенными выше ответами об использовании MutableList, но вы также можете добавить / удалить из списка и получить новый список, как показано ниже.

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

Или

val newListWithElement = existingList.plus(element)
val newListMinusElement = existingList.minus(element)
Динеш Сальве
источник
8

По-видимому, список Kotlin по умолчанию является неизменным. Чтобы иметь список, который может измениться, нужно использовать 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 о том, как коллекция только для чтения обеспечивает лучшее кодирование.

Elye
источник
Вы правильно используете MutableList, однако инициализация с помощью nullне будет работать. Только допустимые или ненулевые утвержденные вызовы разрешены для обнуляемого получателя типа MutableList<Int>.
Фульвио
Это работает на моем конце, и никаких ошибок не найдено. Мне не нужно инициализировать его, если только когда мне это нужно, когдаdoSomething
Elye
@Elye Я знаю, что это старый ответ и вопрос, но использование lateinitвместо того, чтобы сделать список обнуляемым, является правильным способом решения этой проблемы. Не помню, lateinitбыл ли он добавлен с самого начала Kotlin, но сейчас это определенно решение для его использования :-)
Darwind
5

В Kotlin вы должны использовать MutableListили ArrayList.

Посмотрим, как 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) 
}
Энди Федоров
источник
4

Вы можете сделать с созданием нового, как это.

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

Теперь вы можете использовать list2, спасибо.

Дальвиндер Сингх
источник
2

Ограничение изменчивости для строителей

Верхние ответы здесь правильно говорят о разнице в Kotlin между только для чтения List(ПРИМЕЧАНИЕ: это только для чтения, а не «неизменяемый» ), и MutableList.

В общем, следует стремиться использовать списки только для чтения, однако изменчивость все еще часто бывает полезна во время создания , особенно при работе со сторонними библиотеками с нефункциональными интерфейсами. Для случаев, когда альтернативные методы построения недоступны, такие как listOfнепосредственное использование или применение функциональной конструкции, такой как foldили reduce, простая конструкция «функция построителя», подобная следующей, приятно создает список только для чтения из временного изменяемого списка:

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")
}

Теперь вся изменчивость изолирована от одной области блока, используемой для построения списка только для чтения, а остальная часть вашего кода использует список только для чтения, который выводится из компоновщика.

ОБНОВЛЕНИЕ : Начиная с Kotlin 1.3.70, указанная buildListвыше точная функция доступна в стандартной библиотеке в качестве экспериментальной функции вместе с ее аналогами buildSetи buildMap. См. Https://blog.jetbrains.com/kotlin/2020/03/kotlin-1-3-70-released/ .

Раман
источник
спасибо и хорошо работал с бизнес-логикой в ​​методе apply, даже использовал anotherList.ForEach {add (foo)} внутри .appy {}
BENN1TH
1

В концепции неизменяемых данных, возможно, это лучший способ:

class TempClass {
    val list: List<Int> by lazy {
        listOf<Int>()
    }
    fun doSomething() {
        list += 10
        list -= 10
    }
}
bbsimon
источник
1

listНаходится immutableна Default, вы можете использовать ArrayListвместо этого. как это :

 val orders = arrayListOf<String>()

тогда вы можете add/deleteпредметы из этого, как показано ниже:

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

по умолчанию ArrayListэто mutableтак, что вы можете выполнять операции над ним.

гром
источник