Na liście Kotlina brakuje „dodaj”, „usuń”, brak mapy „umieść” itp.?

197

W Javie możemy wykonać następujące czynności

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

Ale jeśli przepiszemy go bezpośrednio do Kotlin, jak poniżej

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

Wystąpił błąd polegający na nie znalezieniu addi removeniedziałaniu z mojej listy

Pracuję nad rzutowaniem go na ArrayList, ale dziwne jest, że trzeba go rzutować, podczas gdy w Javie rzutowanie nie jest wymagane. I to przeczy celowi posiadania abstrakcyjnej listy klas

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

Czy jest jakiś sposób na użycie listy, ale nie muszę jej przesyłać, tak jak to można zrobić w Javie?

Elye
źródło
1
Tylko komentarz, dlaczego nie możesz tego zrobić, myList = nulla później dodaj bez połączenia !!. Możesz temu zaradzić, używając lateinitsłowa kluczowego przed swoją właściwością w lateinit var myList: List<Int>ten sposób : w ten sposób nie będziesz musiał natychmiast inicjować listy, ale gwarantujesz kompilatorowi, że zainicjujesz ją przed pierwszym użyciem listy. Jest to płynniejsze rozwiązanie, ale nakłada na ciebie odpowiedzialność jako programista.
Darwind,

Odpowiedzi:

351

W przeciwieństwie do wielu języków, Kotlin rozróżnia kolekcje zmienne i niezmienne (listy, zestawy, mapy itp.). Precyzyjna kontrola nad tym, kiedy dokładnie można edytować kolekcje, jest przydatna do eliminowania błędów i projektowania dobrych interfejsów API.

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

Musisz użyć MutableListlisty.

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() powinien również działać.

fulvio
źródło
4
Ładna i dobrze napisana odpowiedź.
Wybieram
6
Nie musisz uczynić listy zerową, jeśli ją zainicjujesz natychmiast. Zredagowałem twoją odpowiedź.
Kirill Rakhman,
37

Definiowanie kolekcji list w Kotlinie na różne sposoby:

  • Niezmienna zmienna z niezmienną (tylko do odczytu) listą:

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


  • Niezmienna zmienna z listą zmiennych:

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

    lub bez wartości początkowej - pusta lista i bez jawnego typu zmiennej:

    val users = mutableListOf<User>()
    //or
    val users = ArrayList<User>()
    
    • możesz dodać elementy do listy:
      • users.add(anohterUser) lub
      • users += anotherUser(pod maską to users.add(anohterUser))


  • Zmienna zmienna z niezmienną listą:

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

    lub bez wartości początkowej - pusta lista i bez jawnego typu zmiennej:

    var users = emptyList<User>()
    • UWAGA: możesz dodać * elementy do listy:
      • users += anotherUser - * tworzy nową ArrayList i przypisuje ją do users


  • Zmienna zmienna z listą zmiennych:

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

    lub bez wartości początkowej - pusta lista i bez jawnego typu zmiennej:

    var users = emptyList<User>().toMutableList()
    //or
    var users = ArrayList<User>()
    
    • UWAGA: możesz dodać elementy do listy:
      • users.add(anohterUser)
      • ale nie używa users += anotherUser

        Błąd: Kotlin: Dwuznaczność operatorów przypisań: operator
        publiczny fun Collection.plus (element: String): Lista zdefiniowana w kotlin.collections
        @InlineOnly publiczny operator inline fun MutableCollection.plusAssign (element: String): Jednostka zdefiniowana w kolekcji kotlin.collections


patrz także: https://kotlinlang.org/docs/reference/collections.html

Lukas
źródło
9

Zgadzam się z wszystkimi powyższymi odpowiedziami dotyczącymi korzystania z MutableList, ale możesz także dodać / usunąć z listy i uzyskać nową listę, jak poniżej.

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

Lub

val newListWithElement = existingList.plus(element)
val newListMinusElement = existingList.minus(element)
Dinesh Salve
źródło
8

Najwyraźniej domyślna lista Kotlin jest niezmienna. Aby mieć Listę, którą można zmienić, należy użyć MutableList jak poniżej

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

Zaktualizowano Niemniej jednak nie zaleca się używania MutableList, chyba że lista, którą naprawdę chcesz zmienić. Odnosi się do https://hackernoon.com/read-only-collection-in-kotlin-leads-to-better-coding-40cdfa4c6359, aby dowiedzieć się, jak kolekcja tylko do odczytu zapewnia lepsze kodowanie.

Elye
źródło
Masz rację co do używania MutableList, jednak inicjowanie go nullnie zadziała. Tylko bezpieczne lub niezerowe potwierdzone połączenia są dozwolone na zerowanym odbiorniku typu MutableList<Int>.
fulvio
Działa na moim końcu i nie znaleziono błędu. Nie muszę go inicjować, chyba że będę go potrzebować, kiedydoSomething
Elye,
@Elye Wiem, że to stara odpowiedź i pytanie, ale używanie lateinitzamiast robienia listy zerowej jest właściwym sposobem na rozwiązanie tego problemu. Nie pamiętam jednak, czy lateinitzostał dodany od początku Kotlina, ale obecnie jest to zdecydowanie rozwiązanie, aby go użyć :-)
Darwind
5

W Kotlin musisz użyć MutableListlub ArrayList.

Zobaczmy, jak metody MutableListpracy:

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

Zobaczmy, jak metody ArrayListpracy:

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) 
}
Andy Fedoroff
źródło
4

Możesz zrobić z takim nowym.

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

Teraz możesz używać list2, dziękuję.

Dalvinder Singh
źródło
2

Ograniczanie zmienności do konstruktorów

Najlepsze odpowiedzi tutaj poprawnie mówią o różnicy w Kotlin między tylko do odczytu List(UWAGA: jest tylko do odczytu, a nie „niezmienny” ), i MutableList.

Zasadniczo należy dążyć do korzystania z list tylko do odczytu, jednak zmienność jest często często przydatna w czasie budowy , szczególnie w przypadku bibliotek stron trzecich z niefunkcjonalnymi interfejsami. W przypadkach, w których alternatywne techniki konstrukcyjne nie są dostępne, takie jak listOfbezpośrednie użycie lub zastosowanie konstruktu funkcjonalnego, takiego jak foldlub reduceprosty konstrukt „funkcji konstruktora”, taki jak poniżej, ładnie tworzy listę tylko do odczytu z tymczasowej zmiennej:

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()

i można to ładnie zamknąć w wbudowanej funkcji narzędziowej wielokrotnego użytku:

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

które można nazwać tak:

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

Teraz cała zmienność jest izolowana do jednego zakresu blokowego używanego do budowy listy tylko do odczytu, a reszta kodu używa listy tylko do odczytu, która jest wyprowadzana z programu budującego.

AKTUALIZACJA : Od Kotlin 1.3.70 powyższa dokładna buildListfunkcja jest dostępna w standardowej bibliotece jako funkcja eksperymentalna, wraz z jej analogami buildSeti buildMap. Zobacz https://blog.jetbrains.com/kotlin/2020/03/kotlin-1-3-70-released/ .

Raman
źródło
dzięki i działał dobrze z logiką biznesową w ramach metody zastosowania, nawet używał anotherList.ForEach {add (foo)} wewnątrz .appy {}
BENN1TH
1

W koncepcji niezmiennych danych może to być lepszy sposób:

class TempClass {
    val list: List<Int> by lazy {
        listOf<Int>()
    }
    fun doSomething() {
        list += 10
        list -= 10
    }
}
bbsimon
źródło
1

A listjest immutablegotowe Default, możesz użyć ArrayListzamiast tego. lubię to :

 val orders = arrayListOf<String>()

wtedy możesz add/deleteprzedmioty z tego jak poniżej:

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

domyślnie ArrayListjest mutabletak, abyś mógł wykonywać na nim operacje.

grzmot
źródło