Toán tử dấu hoa thị Kotlin trước tên biến hoặc Toán tử Spread trong Kotlin


97

Tôi muốn biết chính xác dấu hoa thị làm gì trước tên biến trong Kotlin. Tôi thấy điều này ( *args) tại ví dụ 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)
}

Câu trả lời:


163

Nhà *điều hành được gọi là Nhà điều hành Spread trong Kotlin.

Từ Tài liệu tham khảo Kotlin ...

Khi chúng ta gọi một hàm vararg, chúng ta có thể truyền từng đối số một, ví dụ như asList (1, 2, 3) hoặc, nếu chúng ta đã có một mảng và muốn chuyển nội dung của nó vào hàm, chúng ta sử dụng spread toán tử (tiền tố mảng bằng *):

Nó có thể được áp dụng cho một Mảng trước khi chuyển nó vào một hàm chấp nhận varargs.

Ví dụ...

Nếu bạn có một hàm chấp nhận nhiều đối số ...

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

Bạn có thể chuyển một mảng vào nó như vậy ...

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

Ghi chú:

  • Các *nhà điều hành cũng là toán tử nhân (tất nhiên).
  • Toán tử chỉ có thể được sử dụng khi chuyển các đối số cho một hàm. Kết quả của hoạt động không thể được lưu trữ vì nó không mang lại giá trị nào (nó hoàn toàn là đường cú pháp).
  • Lúc đầu, toán tử có thể khiến một số lập trình viên C / C ++ bối rối vì có vẻ như một con trỏ đang bị hủy tham chiếu. Nó không phải là; Kotlin không có khái niệm về con trỏ .
  • Toán tử có thể được sử dụng ở giữa các đối số khác khi gọi một hàm vararg. Điều này được chứng minh trong ví dụ ở đây .
  • Toán tử tương tự như applyhàm trong các ngôn ngữ lập trình hàm khác nhau.

Toán tử Spread có phải là mảng nội tuyến không? Ví dụ cho mảng a = [1, 2, 3] funWithVararg (* a) nội dòng thành funWithVararg (1,2,3)? Ý tôi là ở mức bytecode.
David

22

Ngoài các câu trả lời trực tiếp hướng tới "cái này là gì!?!", Bạn thường gặp trường hợp bạn có Listvà muốn chuyển nó cho một hàm đang mong đợi a vararg. Đối với điều này, chuyển đổi là:

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

Giả sử rằng tham số cuối cùng của someFuncvarargcùng loại như các yếu tố trong danh sách.


Cảm ơn bạn rất nhiều! Điều này nên có trong tài liệu chính thức dưới phần điều hành spread như một thứ cần chú ý khi nhà điều hành spread của bạn không hoạt động.
pleaseesktop

Cảm ơn! Thực sự hữu ích. Tự hỏi "Spread Operator" đằng sau hậu trường là gì? Chỉ là một cách để có được một giá trị kỳ lạ?
Nicolas Jafelle

11

Như được mô tả trong tài liệu, đây là một toán tử spread:

Khi chúng ta gọi một hàm vararg, chúng ta có thể truyền từng đối số một, ví dụ như asList (1, 2, 3) hoặc, nếu chúng ta đã có một mảng và muốn chuyển nội dung của nó vào hàm, chúng ta sử dụng spread toán tử (tiền tố mảng bằng *):

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

5

Nếu một hàm chấp nhận tham số vararg (Số lượng đối số có thể thay đổi) như:

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

Bây giờ để gọi phương thức này, chúng ta có thể làm:

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

Nhưng điều gì sẽ xảy ra nếu chúng ta có những giá trị này trong một mảng, như:

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

sau đó, để gọi phương thức này, chúng ta phải sử dụng toán tử spread, như:

 sum(*array)

Ở đây, * (toán tử spread) sẽ truyền tất cả nội dung của mảng đó.

* mảng tương đương với 1,2,3,4,5

Nhưng chờ một chút, nếu chúng ta gọi nó như thế này thì sao: sum(array) nó sẽ cho chúng ta lỗi thời gian biên dịch Type Mismatch:

Type mismatch.
Required:Int
Found:IntArray

Vấn đề là sumhàm chấp nhận một vararg Inttham số (chấp nhận giá trị như: 1,2,3,4,5) và nếu chúng ta truyền mảng, nó sẽ được truyền dưới dạng IntArray.


4

Trong Java, bạn có thể chuyển một mảng như vậy nhưng một lợi thế của việc giải nén một mảng bằng toán tử spread *là toán tử spread cho phép bạn kết hợp các giá trị từ một mảng và một số giá trị cố định trong một lệnh gọi. Java không hỗ trợ điều này.


Được ủng hộ, bởi vì tôi đã tự hỏi mình tại sao họ lại triển khai nó như thế này. Tôi vẫn không chắc chắn 100% về nó. Ý tôi là, họ không thể suy luận điều này trong hầu hết các trường hợp?
Tim Büthe

1
@ TimBüthe Trong một số trường hợp, không thể suy luận được, hãy xem xét các trường hợp sau val resultOne = arrayOf(intArrayOne, intArrayTwo)val resultTwo = arrayOf(*intArrayOne, *intArrayTwo). Loại resultOneresultTwolần lượt là Array<Int>Array<Array<Int>>. Tôi tin rằng đó là một trong những lý do
Farid
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.