У списку Котліна відсутнє "додати", "видалити", на карті відсутнє "поставити" тощо?


197

На 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 лиття не потрібно. І це перемагає мета створення абстрактного списку класів

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

Чи є у мене спосіб використовувати List, але не потрібно його додавати, як, що можна зробити на Java?


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

Відповіді:


351

На відміну від багатьох мов, Котлін розрізняє змінні та незмінні колекції (списки, набори, карти тощо). Точний контроль того, коли саме можна редагувати колекції, корисний для усунення помилок та для створення хороших 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

Визначення колекції списку в Котліні різними способами:

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

    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 public inline operator fun MutableCollection.plusAssign (елемент: String): Одиниця, визначена в kotlin.collections


дивись також: https://kotlinlang.org/docs/reference/collections.html


9

Погодьтеся з усіма вищезазначеними відповідями щодо використання MutableList, але ви також можете додати / видалити зі списку та отримати новий список, як показано нижче.

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

Або

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

8

Мабуть, Список Котліна за замовчуванням незмінний. Щоб мати список, який міг би змінитися, слід використовувати 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<Int>.
фульвіо

Він працює з мого кінця, і помилки не знайдено. Мені не потрібно ініціалізувати його, якщо тільки мені це потрібно, колиdoSomething
Елі

@Elye Я знаю, що це стара відповідь і питання, але lateinitзамість того, щоб зробити список недійсним, це правильний спосіб вирішити цю проблему. Не пам’ятайте, чи lateinitдодавались з початку Котліна, але це, безумовно, рішення в даний час використовувати його :-)
Дарвінд

5

У Котліні ви повинні використовувати 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

Обмеження змінності будівельникам

Верхні відповіді тут правильно говорять про різницю в Котліні між лише читанням 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")
}

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

ОНОВЛЕННЯ : Станом на Котлін 1.3.70, точна buildListвище функція доступна в стандартній бібліотеці як експериментальна функція разом з її аналогами buildSetта buildMap. Дивіться https://blog.jetbrains.com/kotlin/2020/03/kotlin-1-3-70-released/ .


дякую і добре працював з діловою логікою в рамках методу нанесення, навіть використовував AnotherList.ForEach {add (foo)} всередині .appy {}
BENN1TH

1

В понятті незмінних даних, можливо, це кращий спосіб:

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

1

listЗнаходиться immutableна Default, ви можете використовувати ArrayListзамість цього. подобається це :

 val orders = arrayListOf<String>()

то ви можете add/deleteпункти з цього подібного нижче:

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

за замовчуванням ArrayList- mutableце ви можете виконувати операції над ним.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.