Toán tử double * (splat) làm gì


214

Bạn đã thấy một chức năng khai báo như thế này?

def foo a, **b
  ...
end

Tôi hiểu rằng một đơn *là toán tử splat. Có **nghĩa là gì?

Câu trả lời:


373

Ruby 2.0 đã giới thiệu các đối số từ khóa và **hoạt động như thế *, nhưng đối với các đối số từ khóa. Nó trả về một Hash với các cặp khóa / giá trị.

Đối với mã này:

def foo(a, *b, **c)
  [a, b, c]
end

Đây là bản demo:

> foo 10
=> [10, [], {}]
> foo 10, 20, 30
=> [10, [20, 30], {}]
> foo 10, 20, 30, d: 40, e: 50
=> [10, [20, 30], {:d=>40, :e=>50}]
> foo 10, d: 40, e: 50
=> [10, [], {:d=>40, :e=>50}]

44
Điều này trả lời câu hỏi hoàn hảo, nhưng tôi đã có một phụ lục nhỏ. Giống như toán tử splat có thể được sử dụng trên mảng bạn vượt qua, splat kép có thể được sử dụng trên các giá trị băm. Nếu opts = {d: 40, e: 50}, sau đó foo 10, opts, f: 60sẽ gán {f: 60}cho c, trong khi foo 10, **opts, f: 60sẽ gán {d: 40, e: 50, f: 60}. Để đạt được hiệu ứng thứ hai, trước đây bạn sẽ có merged các mảng rõ ràng.
brymck

Tôi cho rằng điều này hữu ích cho việc thiết lập các tham số băm tùy chọn cho một phương thức
bigpotato

Có lẽ đáng lưu ý rằng nếu trộn các đối số từ khóa với splat từ khóa, thì splat từ khóa cần phải xuất hiện sau các đối số từ khóa.
MrMesees

43

Đó là toán tử splat kép có sẵn kể từ Ruby 2.0.

Nó nắm bắt tất cả các đối số từ khóa (cũng có thể là một hàm băm đơn giản, đó là cách thành ngữ để mô phỏng các đối số từ khóa trước khi chúng trở thành một phần của ngôn ngữ Ruby)

def my_method(**options)
  puts options.inspect
end

my_method(key: "value")

Các mã trên in {key:value}ra bàn điều khiển.

Giống như toán tử splat duy nhất nắm bắt tất cả các đối số thông thường, nhưng thay vì một mảng, bạn nhận được một hàm băm .

Ví dụ thực tế:

Ví dụ trong Rails, cyclephương thức trông như thế này:

def cycle(first_value, *values)
  options = values.extract_options!
  # ...
end

Phương pháp này có thể được gọi như thế này : cycle("red", "green", "blue", name: "colors").

Đây là một mẫu khá phổ biến: Bạn chấp nhận một danh sách các đối số và cái cuối cùng là hàm băm tùy chọn, có thể được trích xuất - ví dụ - sử dụng ActiveSupport extract_options!.

Trong Ruby 2.0, bạn có thể đơn giản hóa các phương thức sau:

def cycle(first_value, *values, **options)
  # Same code as above without further changes!
end

Phải thừa nhận rằng đó chỉ là một cải tiến nhỏ nếu bạn đang sử dụng ActiveSupport nhưng đối với Ruby đơn giản, mã đạt được khá nhiều sự đồng nhất.


20

Ngoài ra, bạn có thể sử dụng nó trong phía người gọi như thế này:

def foo(opts); p opts end
bar = {a:1, b:2}

foo(bar, c: 3)
=> ArgumentError: wrong number of arguments (given 2, expected 1)

foo(**bar, c: 3)
=> {:a=>1, :b=>2, :c=>3}

5
Wow, double-splat là không phù hợp với toán tử trải rộng đối tượng của ES6.
mpoisot

1
Cảm ơn, đó là xác nhận mà tôi đang tìm kiếm.
Qortex
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.