ตัวดำเนินการดอกจัน Kotlin ก่อนชื่อตัวแปรหรือตัวดำเนินการกระจายใน Kotlin


102

ฉันต้องการทราบว่าเครื่องหมายดอกจันทำหน้าที่อะไรก่อนชื่อตัวแปรใน Kotlin ฉันเห็นสิ่งนี้ ( *args) ในตัวอย่างSpring boot Kotlin :

@SpringBootApplication
open class Application {

    @Bean
    open fun init(repository: CustomerRepository) = CommandLineRunner {
        repository.save(Customer("Jack", "Bauer"))
        repository.save(Customer("Chloe", "O'Brian"))
        repository.save(Customer("Kim", "Bauer"))
        repository.save(Customer("David", "Palmer"))
        repository.save(Customer("Michelle", "Dessler"))
    }
}

fun main(args: Array<String>) {
    SpringApplication.run(Application::class.java, *args)
}

คำตอบ:


169

*ผู้ประกอบการเป็นที่รู้จักในฐานะผู้ประกอบการแพร่กระจายใน Kotlin

จากเอกสารอ้างอิง Kotlin ...

เมื่อเราเรียกใช้ฟังก์ชัน vararg เราสามารถส่งอาร์กิวเมนต์ทีละรายการเช่น asList (1, 2, 3) หรือถ้าเรามีอาร์เรย์อยู่แล้วและต้องการส่งผ่านเนื้อหาไปยังฟังก์ชันเราจะใช้การแพร่กระจาย ตัวดำเนินการ (นำหน้าอาร์เรย์ด้วย *):

varargsก็สามารถที่จะนำไปใช้กับอาร์เรย์ก่อนที่จะผ่านมันเข้าไปในฟังก์ชั่นที่ยอมรับ

ตัวอย่างเช่น...

หากคุณมีฟังก์ชันที่รับอาร์กิวเมนต์ที่หลากหลาย ...

fun sumOfNumbers(vararg numbers: Int): Int {
    return numbers.sum()
}

คุณสามารถส่งอาร์เรย์เข้าไปได้เช่นนั้น ...

val numbers = intArrayOf(2, 3, 4)
val sum = sumOfNumbers(*numbers)
println(sum) // Prints '9'

หมายเหตุ:

  • ตัว*ดำเนินการยังเป็นตัวดำเนินการคูณ (แน่นอน)
  • ตัวดำเนินการสามารถใช้ได้เมื่อส่งผ่านอาร์กิวเมนต์ไปยังฟังก์ชันเท่านั้น ไม่สามารถจัดเก็บผลลัพธ์ของการดำเนินการได้เนื่องจากไม่ให้คุณค่า (เป็นน้ำตาลจากปฏิกิริยาล้วนๆ )
  • ตัวดำเนินการอาจสร้างความสับสนให้กับโปรแกรมเมอร์ C / C ++ ในตอนแรกเนื่องจากดูเหมือนว่าตัวชี้จะถูกยกเลิกการอ้างอิง มันไม่ใช่; Kotlin ไม่มีความคิดของพอยน์เตอร์
  • ตัวดำเนินการสามารถใช้ระหว่างอาร์กิวเมนต์อื่น ๆเมื่อเรียกใช้ฟังก์ชัน vararg นี่คือการแสดงในตัวอย่างที่นี่
  • ตัวดำเนินการจะคล้ายกับapplyฟังก์ชันในภาษาโปรแกรมการทำงานต่างๆ

ตัวดำเนินการกระจายเป็นอาร์เรย์อินไลน์หรือไม่ ตัวอย่างเช่นอาร์เรย์ a = [1, 2, 3] funWithVararg (* a) แทรกใน funWithVararg (1,2,3)? ฉันหมายถึงระดับ bytecode
David

23

นอกเหนือไปจากคำตอบที่มีโดยตรงต่อ "สิ่งที่เป็นสิ่งนี้!?!" คุณมักจะมีกรณีที่คุณมีและต้องการที่จะผ่านไปยังฟังก์ชั่นที่ได้รับการคาดหวังว่าจะได้List varargสำหรับสิ่งนี้การแปลงคือ:

someFunc(x, y, *myList.toTypedArray())

สมมติว่าพารามิเตอร์สุดท้ายของsomeFuncเป็นvarargประเภทเดียวกับองค์ประกอบในรายการ


ขอบคุณมาก! สิ่งนี้ควรอยู่ในเอกสารอย่างเป็นทางการภายใต้ส่วนตัวดำเนินการกระจายซึ่งเป็นสิ่งที่ต้องระวังเมื่อตัวดำเนินการสเปรดของคุณไม่ทำงาน
happyesktop

ขอบคุณ! เป็นประโยชน์จริงๆ สงสัยว่าเบื้องหลัง "Spread Operator" คืออะไร? เป็นเพียงวิธีการรับค่า varargs หรือไม่?
Nicolas Jafelle

11

ตามที่อธิบายไว้ในเอกสารนี้เป็นตัวดำเนินการกระจาย:

เมื่อเราเรียกใช้ฟังก์ชัน vararg เราสามารถส่งอาร์กิวเมนต์ทีละรายการเช่น asList (1, 2, 3) หรือถ้าเรามีอาร์เรย์อยู่แล้วและต้องการส่งผ่านเนื้อหาไปยังฟังก์ชันเราจะใช้การแพร่กระจาย ตัวดำเนินการ (นำหน้าอาร์เรย์ด้วย *):

val a = arrayOf(1, 2, 3) 
val list = asList(-1, 0, *a, 4)

6

หากฟังก์ชันที่ยอมรับพารามิเตอร์ vararg (จำนวนอาร์กิวเมนต์ตัวแปร) เช่น:

fun sum(vararg data:Int)
{
   // function body here         
}

ตอนนี้เรียกวิธีนี้เราสามารถทำได้:

sum(1,2,3,4,5)

แต่ถ้าเรามีค่าเหล่านี้ในอาร์เรย์เช่น:

val array= intArrayOf(1,2,3,4,5)

จากนั้นในการเรียกวิธีนี้เราต้องใช้ตัวดำเนินการกระจายเช่น:

 sum(*array)

ที่นี่ * (ตัวดำเนินการกระจาย) จะส่งผ่านเนื้อหาทั้งหมดของอาร์เรย์นั้น

* อาร์เรย์เทียบเท่ากับ1,2,3,4,5

แต่เดี๋ยวก่อนถ้าเราเรียกแบบนี้sum(array) มันจะทำให้เรามีข้อผิดพลาดเวลาคอมไพล์ Type Mismatch:

Type mismatch.
Required:Int
Found:IntArray

ปัญหาคือsumฟังก์ชั่นยอมรับvararg Intพารามิเตอร์ (ซึ่งยอมรับค่าที่ชอบ: 1,2,3,4,5) IntArrayและถ้าเราผ่านอาร์เรย์ก็จะถูกส่งผ่านเป็น


5

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


1
โหวตขึ้นเพราะฉันถามตัวเองว่าทำไมพวกเขาถึงใช้แบบนี้ ฉันยังไม่แน่ใจ 100% เกี่ยวกับเรื่องนี้ ฉันหมายความว่าพวกเขาไม่สามารถสรุปสิ่งนี้ได้ในกรณีส่วนใหญ่?
Tim Büthe

1
@ TimBütheในบางกรณีก็จะไม่เป็นไปได้ที่จะสรุปว่าให้พิจารณากรณีดังต่อไปและval resultOne = arrayOf(intArrayOne, intArrayTwo) val resultTwo = arrayOf(*intArrayOne, *intArrayTwo)ประเภทresultOneและresultTwoเป็นลำดับและArray<Int> Array<Array<Int>>ฉันเชื่อว่านั่นเป็นหนึ่งในเหตุผล
Farid
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.