Apa arti param: _ * di Scala?

87

Karena baru mengenal Scala (2.9.1), saya memiliki List[Event]dan ingin menyalinnya ke a Queue[Event], tetapi Sintaks berikut menghasilkan aQueue[List[Event]] :

val eventQueue = Queue(events)

Untuk beberapa alasan, berikut ini berfungsi:

val eventQueue = Queue(events : _*)

Tapi saya ingin memahami apa fungsinya, dan mengapa itu berhasil? Saya sudah melihat tanda tangan dariQueue.apply fungsinya:

def apply[A](elems: A*)

Dan saya mengerti mengapa upaya pertama tidak berhasil, tetapi apa arti upaya kedua? Apa :, dan _*dalam kasus ini, dan mengapa fungsinya tidak applymengambil begitu saja Iterable[A]?

Chris
sumber

Jawaban:

93

a: Aadalah tipe anggapan; lihat Apa tujuan dari jenis ascriptions di Scala?

: _* adalah turunan khusus dari tipe ascription yang memberi tahu kompilator untuk memperlakukan argumen tunggal dari tipe urutan sebagai urutan argumen variabel, yaitu varargs.

Ini sepenuhnya valid untuk membuat Queuepenggunaan Queue.applyyang memiliki elemen tunggal yang berurutan atau dapat diulang, jadi inilah yang terjadi ketika Anda memberikan satu Iterable[A].

Ben James
sumber
83

Ini adalah notasi khusus yang memberi tahu kompilator untuk meneruskan setiap elemen sebagai argumennya sendiri, bukan semuanya sebagai argumen tunggal. Lihat disini .

Ini adalah jenis anotasi yang menunjukkan argumen urutan dan disebutkan sebagai "pengecualian" untuk aturan umum di bagian 4.6.2 dari spesifikasi bahasa, "Parameter Berulang".

Ini berguna ketika suatu fungsi mengambil sejumlah variabel argumen, misalnya fungsi seperti def sum(args: Int*), yang dapat dipanggil sebagai sum(1), sum(1,2)dll. Jika Anda memiliki daftar seperti xs = List(1,2,3), Anda tidak dapat melewatkannya xssendiri, karena ini adalah a Listdaripada Int, tetapi Anda dapat meneruskan elemennya menggunakan sum(xs: _*).

Luigi Plinge
sumber
def sum(xs: _*)melempar 'kesalahan: jenis wildcard tidak terikat'
7kemZmani
Jawaban Anda jelas, tetapi ini sebenarnya membuat lebih banyak kebingungan bagi saya, biasanya dalam scala xs: intberarti tipe xs adalah int, dengan itu adalah sintaks di atas dalam scala di mana xs: _*cara xs dicor ke masing-masing anggota.
Rpant
Mengikuti tautan di atas dan terlihat seperti itu, tipe askripsi adalah terminologi skala untuk casting tipe java. Harap perbaiki saya jika salah.
Rpant
2
@ 7kemZmani: Anda harus mendefinisikan fungsi dengan spesifik jenis var-args: def sum(args: Int*)dan Anda menyebutnya dengan wildcard jenis "generik" var-args: val a = sum(xs: _*). Anggap saja _*sebagai "Saya meneruskan Int *, atau String *, atau apa pun * yang ditentukan dalam tanda tangan metode"
Alfonso Nishikawa
10

Untuk orang-orang Python:

Operator Scala _*kurang lebih setara dengan * -operator Python .


Contoh

Mengonversi contoh skala dari tautan yang disediakan oleh Luigi Plinge :

def echo(args: String*) = 
    for (arg <- args) println(arg)

val arr = Array("What's", "up", "doc?")
echo(arr: _*)

ke Python akan terlihat seperti:

def echo(*args):
    for arg in args:
        print "%s" % arg

arr = ["What's", "up", "doc?"]
echo(*arr)

dan keduanya memberikan hasil sebagai berikut:

Apa
up
doc?


Perbedaannya: membongkar parameter posisi

Sedangkan Python * -operator juga dapat menangani pembongkaran parameter / parameter posisi untuk fungsi fixed-arity:

def multiply (x, y):
    return x * y

operands = (2, 4)
multiply(*operands)

8

Melakukan hal yang sama dengan Scala:

def multiply(x:Int, y:Int) = {
    x * y;
}

val operands = (2, 4)
multiply (operands : _*)

akan gagal:

tidak cukup argumen untuk metode multiply: (x: Int, y: Int) Int.
Parameter nilai tidak ditentukan y.

Tetapi dimungkinkan untuk mencapai hal yang sama dengan scala:

def multiply(x:Int, y:Int) = {
    x*y;
}

val operands = (2, 4)
multiply _ tupled operands

Menurut Lorrin Nelson inilah cara kerjanya:

Bagian pertama, f _, adalah sintaks untuk fungsi yang diterapkan sebagian di mana tidak ada argumen yang ditentukan. Ini bekerja sebagai mekanisme untuk mendapatkan objek fungsi. tupled mengembalikan fungsi baru dari arity-1 yang mengambil satu tupel arity-n.

Bacaan selanjutnya:

Murmel
sumber