รายการของ Kotlin หายไป“ เพิ่ม”,“ ลบ”, แผนที่ขาดหายไป“ ใส่” ฯลฯ ?


200

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

ฉันพบข้อผิดพลาดในการไม่ค้นหา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>วิธีนี้คุณไม่จำเป็นต้องเริ่มต้นรายการทันที แต่คุณรับประกันกับคอมไพเลอร์ที่คุณจะเริ่มต้นมันก่อนที่จะใช้รายการในครั้งแรก มันเป็นทางออกที่ราบรื่นกว่า แต่มันทำให้คุณมีความรับผิดชอบในฐานะนักพัฒนา
Darwind

คำตอบ:


355

ซึ่งแตกต่างจากหลายภาษา 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
คุณไม่จำเป็นต้องทำให้รายการเป็นโมฆะถ้าคุณเริ่มต้นทันที ฉันแก้ไขคำตอบของคุณ
Kirill Rakhman

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: ความคลุมเครือของโอเปอเรเตอร์ที่กำหนด:
        ความสนุกของผู้ดำเนินการสาธารณะ Collection.plus (องค์ประกอบ: สตริง): รายการที่กำหนดใน kotlin.collections
        @InlineOnly ผู้ดำเนินการอินไลน์สาธารณะสนุก MutableCollection.plusAssign (องค์ประกอบ: สตริง): หน่วยที่กำหนดใน 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

เห็นได้ชัดว่ารายการเริ่มต้นของ 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สำหรับวิธีการรวบรวมแบบอ่านอย่างเดียวที่ให้การเข้ารหัสที่ดีขึ้น


คุณถูกต้องเกี่ยวกับการใช้MutableListอย่างไรก็ตามการเริ่มต้นด้วยnullจะไม่ทำงาน อนุญาตเฉพาะการโทรที่ปลอดภัยหรือไม่เป็นโมฆะเท่านั้นที่อนุญาตให้ใช้กับตัวรับชนิดที่MutableList<Int>ไม่สามารถใช้ได้
fulvio

มันทำงานได้ในตอนท้ายของฉันและไม่พบข้อผิดพลาด ฉันไม่จำเป็นต้องกำหนดค่าเริ่มต้นยกเว้นเมื่อฉันต้องการเมื่อdoSomething
Elye

@Elye ฉันรู้ว่านี่เป็นคำตอบและคำถามเก่า แต่การใช้lateinitแทนที่จะทำให้รายการเป็นโมฆะเป็นวิธีที่เหมาะสมในการแก้ไขปัญหานี้ จำไม่ได้ว่าlateinitได้รับมาจากจุดเริ่มต้นของ Kotlin แม้ว่า แต่นี้เป็นมั่นเหมาะวิธีการแก้ปัญหาในปัจจุบันจะใช้มัน :-)
Darwind

5

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

4

คุณสามารถสร้างใหม่ได้เช่นนี้

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

ตอนนี้คุณสามารถใช้ list2 ได้แล้วขอบคุณ


3

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

ตามลิงค์ข้างต้น List <E> นั้นไม่เปลี่ยนรูปใน Kotlin อย่างไรก็ตามสิ่งนี้จะได้ผล:

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

นั่นหมายความว่าlist2เป็นรายการที่ไม่แน่นอนดูstackoverflow.com/questions/43114367/...
CoolMind

2

Confining Mutability ให้กับผู้สร้าง

ด้านบนคำตอบที่นี่ได้อย่างถูกต้องพูดคุยกับความแตกต่างใน 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")
}

ตอนนี้ความผันแปรทั้งหมดถูกแยกออกเป็นขอบเขตบล็อกหนึ่งที่ใช้สำหรับการสร้างรายการอ่านอย่างเดียวและส่วนที่เหลือของรหัสของคุณใช้รายการอ่านอย่างเดียวที่ส่งออกจากตัวสร้าง

UPDATE : ณ Kotlin 1.3.70, ที่แน่นอนbuildListฟังก์ชั่นข้างต้นเป็นใช้ได้ในห้องสมุดมาตรฐานเป็นฟังก์ชั่นการทดลองพร้อมกับ analogues ของตนและ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

A listคือimmutableโดยDefaultคุณสามารถใช้ArrayListแทน แบบนี้ :

 val orders = arrayListOf<String>()

จากนั้นคุณสามารถadd/deleteรายการจากนี้เช่นด้านล่าง:

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

โดยค่าเริ่มต้นArrayListคือmutableเพื่อให้คุณสามารถดำเนินการกับมัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.