0Pricing
Kotlin Academy · บทเรียน

ความแปรผัน ณ จุดประกาศ

in และ out

ความแปรผัน ณ จุดประกาศ เป็นบทเรียน Kotlin Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Kotlin Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Kotlin Academy มีบทเรียนทั้งหมด 4 บทเรียน

ปัญหาของความแปรผัน

List<String> เป็นชนิดหนึ่งของ List<Any> หรือไม่ บางครั้งใช่ และบางครั้งไม่ใช่ ความแปรผันอธิบายว่าชนิดข้อมูลเจเนอริกมีความสัมพันธ์กันอย่างไรเมื่อพารามิเตอร์ชนิดข้อมูลของทั้งสองมีความสัมพันธ์กัน Kotlin ใช้ out และ in เพื่อแสดงความสัมพันธ์นี้

ไม่แปรผันเป็นค่าเริ่มต้น

โดยค่าเริ่มต้น เจเนอริกส์จะ ไม่แปรผัน: Box<String> ไม่ใช่ Box<Any> แม้ว่า String จะเป็นชนิดข้อมูลย่อยของ Any ก็ตาม วิธีนี้ช่วยป้องกันการดำเนินการที่ไม่ปลอดภัย

class Box<T>(val value: T)

fun main() {
    val strBox = Box("hi")
    // val anyBox: Box<Any> = strBox // would not compile
    println(strBox.value)
}

ความแปรผันร่วมด้วย out

การกำหนดพารามิเตอร์ชนิดข้อมูลเป็น out จะทำให้เกิด ความแปรผันร่วม: Producer<String> จะกลายเป็นชนิดข้อมูลย่อยของ Producer<Any> ชนิดข้อมูลนี้สามารถปรากฏได้เฉพาะในตำแหน่ง ผลลัพธ์ เช่น ชนิดข้อมูลที่ส่งคืน

class Producer<out T>(private val item: T) {
    fun produce(): T = item
}

fun main() {
    val strProducer: Producer<String> = Producer("hello")
    val anyProducer: Producer<Any> = strProducer
    println(anyProducer.produce())
}

เหตุใด out จึงปลอดภัย

หากคลาสสร้างหรือส่งคืน T เพียงอย่างเดียวและไม่รับค่าเข้ามา การมอง Producer<String> เป็น Producer<Any> ก็ปลอดภัย เพราะ String ทุกค่าที่ส่งคืนมาก็เป็น Any เช่นกัน

out ในไลบรารีมาตรฐาน

List<out E> แบบอ่านอย่างเดียวของ Kotlin มีความแปรผันร่วม นี่จึงเป็นเหตุผลที่สามารถใช้ List<String> ในตำแหน่งที่ต้องการ List<Any> ได้

fun printAll(items: List<Any>) {
    items.forEach { println(it) }
}

fun main() {
    val names: List<String> = listOf("Ann", "Bob")
    printAll(names)
}

ความแปรผันย้อนด้วย in

การกำหนดพารามิเตอร์ชนิดข้อมูลเป็น in จะทำให้เกิด ความแปรผันย้อน: Consumer<Any> จะกลายเป็นชนิดข้อมูลย่อยของ Consumer<String> ชนิดข้อมูลนี้สามารถปรากฏได้เฉพาะในตำแหน่ง ข้อมูลเข้า เช่น พารามิเตอร์

class Consumer<in T> {
    fun consume(item: T) {
        println("Consumed $item")
    }
}

fun main() {
    val anyConsumer: Consumer<Any> = Consumer()
    val strConsumer: Consumer<String> = anyConsumer
    strConsumer.consume("hi")
}

เหตุใด in จึงปลอดภัย

ผู้รับข้อมูลที่รับ Any ได้ย่อมรับ String ได้แน่นอน ดังนั้น Consumer<Any> จึงสามารถใช้แทนที่ใดก็ตามที่ต้องการ Consumer<String> ได้

หลักช่วยจำผู้ผลิตและผู้รับข้อมูล

โปรดจำหลักว่า Producer ขยาย และ Consumer อยู่เหนือกว่า หรือในคำศัพท์ของ Kotlin คือ out สำหรับผู้ผลิต ซึ่งเป็นข้อมูลออก และ in สำหรับผู้รับข้อมูล ซึ่งเป็นข้อมูลเข้า ชนิดข้อมูลที่ส่งออก T เพียงอย่างเดียวให้ใช้ out ส่วนชนิดข้อมูลที่รับ T เข้าเพียงอย่างเดียวให้ใช้ in

การใช้ in และ out ร่วมกัน

พารามิเตอร์ชนิดข้อมูลที่ใช้ทั้งกับข้อมูลเข้าและข้อมูลออก เช่น ในลิสต์ที่เปลี่ยนแปลงได้ จะต้องคงเป็นชนิดที่ไม่แปรผัน ชนิดข้อมูลฟังก์ชันแสดงให้เห็นทั้งสองแบบ: พารามิเตอร์เป็น in ส่วนค่าที่ส่งคืนเป็น out

fun main() {
    val f: (Number) -> Int = { it.toInt() }
    val g: (Int) -> Number = f
    println(g(3.0.let { Number::class; 5 }))
}

ความแปรผัน ณ จุดประกาศหมายถึงประกาศครั้งเดียว

ความแปรผัน ณ จุดประกาศจะประกาศเพียงครั้งเดียวที่ตัวคลาสด้วย in/out จากนั้นการใช้คลาสทุกครั้งจะได้รับความแปรผันโดยอัตโนมัติ ต่างจาก Java ที่ต้องเขียนไวลด์การ์ดซ้ำทุกครั้งที่ใช้งาน

การเลือก in หรือ out

ให้ถามว่า คลาสนี้สร้างหรือส่งคืน T เพียงอย่างเดียวหรือไม่ หากใช่ให้ใช้ out รับ T เพียงอย่างเดียวหรือไม่ หากใช่ให้ใช้ in หรือทำทั้งสองอย่าง หากทำทั้งสองอย่างให้ปล่อยไว้โดยไม่แปรผัน การเลือกตัวปรับแต่งให้ตรงกับบทบาทจะทำให้ชนิดข้อมูลเจเนอริกยืดหยุ่นและปลอดภัย

ตรวจสอบอย่างรวดเร็ว

ตัวปรับแต่ง out แสดงถึงอะไร

ทบทวน

โดยค่าเริ่มต้น เจเนอริกส์จะไม่แปรผัน ใช้ out สำหรับความแปรผันร่วมเมื่อชนิดข้อมูลสร้างหรือส่งคืนค่าเพียงอย่างเดียว และใช้ in สำหรับความแปรผันย้อนเมื่อชนิดข้อมูลรับค่าเพียงอย่างเดียว โปรดจำว่าผู้ผลิตใช้ out และผู้รับข้อมูลใช้ in ต่อไปคุณจะใช้ความแปรผัน ณ จุดใช้งานด้วยการฉายชนิดข้อมูล

คำถามที่พบบ่อย

บทเรียน “ความแปรผัน ณ จุดประกาศ” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “ความแปรผัน ณ จุดประกาศ” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Kotlin Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Kotlin Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “ความแปรผัน ณ จุดประกาศ”

in และ out คุณปฏิบัติ Kotlin Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Kotlin Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Kotlin Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน

บทเรียน “ความแปรผัน ณ จุดประกาศ” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Kotlin Academy นี้ได้ไหม

ได้ บทเรียน Kotlin Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. ฟังก์ชันและคลาสแบบเจเนอริก
  2. ความแปรผัน ณ จุดประกาศ
  3. ความแปรผัน ณ จุดใช้งาน
  4. ข้อจำกัดของเจเนอริก
← กลับไปที่ Kotlin Academy