Param: _ * có nghĩa là gì trong Scala?


87

Là người mới sử dụng Scala (2.9.1), tôi có một List[Event]và muốn sao chép nó thành a Queue[Event], nhưng Cú pháp sau mang lại một Queue[List[Event]]thay thế:

val eventQueue = Queue(events)

Vì một số lý do, các hoạt động sau đây:

val eventQueue = Queue(events : _*)

Nhưng tôi muốn hiểu nó làm gì và tại sao nó hoạt động? Tôi đã xem chữ ký của Queue.applyhàm:

def apply[A](elems: A*)

Và tôi hiểu tại sao lần thử đầu tiên không thành công, nhưng ý nghĩa của lần thứ hai là gì? Là gì :, và _*trong trường hợp này, và tại sao không phải là applychức năng chỉ có một Iterable[A]?

Câu trả lời:


93

a: Alà loại ascription; xem Mục đích của loại mô tả trong Scala là gì?

: _* là một trường hợp đặc biệt của kiểu ascription yêu cầu trình biên dịch coi một đối số duy nhất của kiểu trình tự là một chuỗi đối số biến, tức là varargs.

Việc tạo Queuesử dụng Queue.applycó một phần tử duy nhất là một chuỗi hoặc có thể lặp lại là hoàn toàn hợp lệ , vì vậy đây chính xác là những gì sẽ xảy ra khi bạn cung cấp một phần tử duy nhất Iterable[A].


83

Đây là một ký hiệu đặc biệt yêu cầu trình biên dịch chuyển từng phần tử làm đối số của riêng nó, thay vì tất cả chúng dưới dạng một đối số duy nhất. Xem tại đây .

Nó là một chú thích kiểu chỉ ra một đối số trình tự và được đề cập như một "ngoại lệ" đối với quy tắc chung trong phần 4.6.2 của đặc tả ngôn ngữ, "Tham số lặp lại".

Nó hữu ích khi một hàm nhận một số đối số thay đổi, ví dụ như một hàm chẳng hạn def sum(args: Int*), có thể được gọi là sum(1), sum(1,2)v.v. Nếu bạn có một danh sách như vậy xs = List(1,2,3), bạn không thể chuyển xschính nó, vì nó là một Listthay vì Int, nhưng bạn có thể chuyển các phần tử của nó bằng cách sử dụng sum(xs: _*).


def sum(xs: _*)ném 'lỗi: không ràng buộc kiểu ký tự đại diện'
7kemZmani

Câu trả lời của bạn là rõ ràng, nhưng điều này thực sự gây ra nhiều nhầm lẫn hơn cho tôi, thường trong scala xs: intcó nghĩa là loại xs là int, đi theo đó là cú pháp ở trên trong scala xs: _*có nghĩa là xs được truyền cho các thành viên riêng lẻ của nó.
Rpant

Đã theo liên kết ở trên và trông giống như nó là vậy, gõ ascription là một thuật ngữ theo tỉ lệ để truyền kiểu java. Xin vui lòng sửa cho tôi nếu sai.
Rpant 25/09/17

2
@ 7kemZmani: Bạn phải xác định chức năng với một cụ var-args loại: def sum(args: Int*)và bạn gọi nó với các ký tự đại diện kiểu "chung chung" var-args: val a = sum(xs: _*). Hãy nghĩ về việc _*"Tôi đang chuyển một Int *, hoặc một chuỗi * hoặc bất cứ thứ gì * được xác định trong chữ ký phương thức"
Alfonso Nishikawa

10

Đối với người dùng Python:

_*Toán tử của Scala tương đương với toán tử * của Python .


Thí dụ

Chuyển đổi ví dụ về scala từ liên kết do Luigi Plinge cung cấp :

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

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

sang Python sẽ giống như sau:

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

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

và cả hai đều cho kết quả sau:

Có gì
lên
doc?


Sự khác biệt: giải nén các tham số vị trí

Trong khi *-operator của Python cũng có thể xử lý việc giải nén các tham số / tham số vị trí cho các hàm fixed-arity:

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

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

số 8

Làm tương tự với Scala:

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

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

sẽ thất bại:

không đủ đối số cho phương thức nhân: (x: Int, y: Int) Int.
Tham số giá trị không xác định y.

Nhưng có thể đạt được điều tương tự với scala:

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

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

Theo Lorrin Nelson, đây là cách nó hoạt động:

Phần đầu tiên, f _, là cú pháp của một hàm được áp dụng một phần trong đó không có đối số nào được chỉ định. Điều này hoạt động như một cơ chế để có được một đối tượng chức năng. tupled trả về một hàm mới của arity-1 nhận một tuple arity-n duy nhất.

Đọc thêm:

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.