ตัวดำเนินการ double * (splat) ทำอะไร


214

คุณเคยเห็นฟังก์ชันที่ประกาศเช่นนี้หรือไม่?

def foo a, **b
  ...
end

ฉันเข้าใจว่าตัวเดียว*เป็นตัวดำเนินการสีแดง อะไร**หมายถึง?

คำตอบ:


373

Ruby 2.0 แนะนำอาร์กิวเมนต์คำหลักและ**ทำหน้าที่เหมือน*แต่สำหรับอาร์กิวเมนต์คำหลัก ส่งคืนแฮชที่มีคู่ของคีย์ / ค่า

สำหรับรหัสนี้:

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

นี่คือตัวอย่าง:

> 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
นี่ตอบคำถามได้อย่างสมบูรณ์แบบ แต่ฉันมีภาคผนวกเล็กน้อย เช่นเดียวกับตัวดำเนินการเครื่องหมายแดงที่สามารถใช้กับอาร์เรย์ที่คุณส่งผ่านเครื่องหมายคู่นั้นสามารถใช้กับแฮชได้ หากopts = {d: 40, e: 50}แล้วfoo 10, opts, f: 60จะกำหนด{f: 60}ไปcในขณะที่จะกำหนดfoo 10, **opts, f: 60 {d: 40, e: 50, f: 60}เพื่อให้ได้เอฟเฟกต์ที่สองก่อนหน้านี้คุณต้องมีmergeอาร์เรย์อย่างชัดเจน
brymck

ฉันจะสมมติว่าสิ่งนี้มีประโยชน์สำหรับการตั้งค่าพารามิเตอร์แฮชที่เป็นทางเลือกสำหรับวิธีการ
bigpotato

น่าจะเป็นสิ่งที่ควรทราบว่าหากการผสมคำหลักกับอาร์กิวเมนต์คำหลักเครื่องหมายคำหลักต้องมาหลังจากอาร์กิวเมนต์ของคำหลัก
MrMesees

43

นั่นคือโอเปอเรเตอร์สแลทคู่ที่มีให้ตั้งแต่ Ruby 2.0

มันรวบรวมอาร์กิวเมนต์ของคำหลักทั้งหมด(ซึ่งอาจเป็นแฮชแบบง่ายซึ่งเป็นวิธีที่ใช้ในการเลียนแบบการขัดแย้งของคำหลักก่อนที่จะกลายเป็นส่วนหนึ่งของภาษา Ruby)

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

my_method(key: "value")

โค้ดด้านบน{key:value}จะพิมพ์ไปที่คอนโซล

เช่นเดียวกับผู้ประกอบการเครื่องหมายเดียวจับข้อโต้แย้งปกติ แต่แทนที่จะเป็นอาร์เรย์คุณจะได้รับกัญชา

ตัวอย่างชีวิตจริง:

ตัวอย่างเช่นใน Rails cycleวิธีที่มีลักษณะเช่นนี้:

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

วิธีการนี้สามารถเรียกได้ดังนี้: cycle("red", "green", "blue", name: "colors").

นี้ค่อนข้างรูปแบบทั่วไป: คุณยอมรับรายการของอาร์กิวเมนต์และสุดท้ายคือแฮตัวเลือกซึ่งสามารถเป็นสารสกัด - ตัวอย่างเช่น - ใช้ extract_options!ActiveSupport

ใน Ruby 2.0 คุณสามารถทำให้วิธีการเหล่านี้ง่ายขึ้น:

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

เป็นที่ยอมรับว่าเป็นการปรับปรุงเล็กน้อยหากคุณใช้ ActiveSupport อยู่แล้ว แต่สำหรับ Ruby ธรรมดารหัสจะได้รับความกระชับค่อนข้างมาก


20

นอกจากนี้คุณสามารถใช้มันในฝั่งผู้โทรเช่นนี้:

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
ว้าวเครื่องหมายสองครั้งนั้นคล้ายคลึงกันกับโอเปอเรเตอร์การแพร่กระจายวัตถุของ ES6
mpoisot

1
ขอบคุณนั่นคือการยืนยันที่ฉันกำลังมองหา
Qortex
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.