สิ่งหนึ่งที่ฉันชอบเกี่ยวกับ Ruby คือความลึกซึ้งของฟีเจอร์ คุณสามารถใช้โอเปอเรเตอร์ได้ แต่ลองขุดดูสักนิดแล้วคุณจะพบว่าคุณแค่ขีดข่วนพื้นผิวของสิ่งที่มันสามารถทำได้เท่านั้น ตัวดำเนินการ splat ต่ำต้อย (*
และ **
) เป็นตัวอย่างที่ดี
คุณอาจเคยใช้เครื่องหมายสำหรับอาร์กิวเมนต์ "จับทั้งหมด" และนั่นคือสิ่งที่คนส่วนใหญ่ใช้
def go(x, *args)
puts args.inspect
end
go("a", "b", "c")
หากคุณกำลังใช้ไวยากรณ์อาร์กิวเมนต์คีย์เวิร์ด newfangled ให้ใช้ double splat ดังนี้:
def go(**params)
puts params.inspect
end
go(x: 100, y: 200)
สิ่งนี้มีประโยชน์ แต่คุณสามารถใช้ splats ได้มากขึ้น มาดำน้ำกันเถอะ!
การใช้อาร์เรย์เพื่อส่งผ่านหลายอาร์กิวเมนต์
ไม่เพียงแต่คุณสามารถใช้ splats เมื่อกำหนดเมธอด แต่คุณยังสามารถใช้ splats เมื่อเรียกใช้เมธอดได้ด้วย ช่วยให้คุณส่งผ่านอาร์เรย์ไปยังฟังก์ชันที่ต้องการอาร์กิวเมนต์หลายตัว รายการแรกในอาร์เรย์จะกลายเป็นอาร์กิวเมนต์แรก รายการที่สองกลายเป็นอาร์กิวเมนต์ที่สองเป็นต้น
def go(x, y)
end
point = [12, 10]
go(*point)
และอย่าลืมว่าคุณสามารถใช้เครื่องหมายคู่สำหรับอาร์กิวเมนต์คำหลักรูปแบบใหม่ได้:
def go(x:, y:)
end
point = { x: 100, y: 200 }
go(**point)
ไม่ต้องไปต่อท้าย
แม้ว่าจะเป็นเรื่องปกติที่จะใส่อาร์กิวเมนต์แบบกระจายที่ส่วนท้ายของรายการอาร์กิวเมนต์ แต่ก็ไม่มีกฎหมายที่กำหนดให้ใช้
คุณสามารถใส่เครื่องหมายที่ใดก็ได้ในรายการอาร์กิวเมนต์
def go(x, *args, y)
puts x # => 1
puts y # => 5
puts args.inspect # => [2,3,4]
end
go(1, 2, 3, 4, 5)
การทำลายอาร์เรย์
กลเม็ดเหล่านี้ทั้งหมดที่มีการโต้แย้งเป็นเพียงกรณีพิเศษของการทำลายโครงสร้างอาร์เรย์
ในกรณีที่คุณไม่คุ้นเคยกับคำว่า "array destructuring" ก็หมายถึงการแยกอาร์เรย์ออกเป็นแต่ละรายการ ดูเหมือนว่านี้:
a, b = [1, 2]
puts a
# 1
puts b
# 2
ใช้งานได้ดี แต่อาจเป็นเรื่องยากที่ต้องระบุตัวแปรเพื่อเก็บทุกรายการในอาร์เรย์ ตัวดำเนินการ splat หลีกเลี่ยงสิ่งนี้ - ทำหน้าที่เหมือนสัญลักษณ์แทน มาดูตัวอย่างกันสักหน่อย
เปิดรายการแรกจากอาร์เรย์
ในบางครั้ง การสามารถดึงรายการแรกออกจากอาร์เรย์ได้โดยไม่ต้องเปลี่ยนอาร์เรย์เดิมจะเป็นประโยชน์ นั่นคือสิ่งที่ตัวอย่างนี้ทำ
first, *remainder = [1, 2, 3, 4, 5]
first
# => 1
remainder
# => [2, 3, 4, 5]
หากคุณต้องการเพียงรายการแรกแต่ไม่ต้องการส่วนที่เหลือของอาร์เรย์ คุณสามารถใช้ไวยากรณ์:
first, * = [1, 2, 3, 4, 5]
first
# => 1
เปิดรายการสุดท้าย
หากต้องการดึงรายการออกจากจุดสิ้นสุดของอาร์เรย์แทนที่จะเป็นจุดเริ่มต้น ให้ติดเครื่องหมายที่จุดเริ่มต้นดังนี้:
*prefix, last = [1, 2, 3, 4, 5]
last
# => 5
prefix
# => [1, 2, 3, 4]
อีกครั้ง หากเราไม่ต้องการตัวแปรเฉพาะ เราก็ไม่ต้องกำหนด:
รับ n รายการแรกและ n รายการสุดท้ายของอาร์เรย์
หากคุณใส่โอเปอเรเตอร์ splat ไว้ตรงกลาง คุณสามารถดึงไอเท็มออกจากปลายแต่ละด้านของอาร์เรย์ได้ตามต้องการ
first, *, last = [1, 2, 3, 4, 5]
first
# => 1
last
# => 5
ข้อจำกัด
เมื่อใช้ตัวดำเนินการ splat ในการทำลายโครงสร้างอาร์เรย์ คุณยังต้องระบุตำแหน่งของรายการอาร์เรย์ที่สัมพันธ์กับจุดเริ่มต้นและจุดสิ้นสุดของอาร์เรย์ ดังนั้นจึงไม่ใช่เครื่องมือที่ดีที่สุดในการแยกรายการออกจากแถวกลางของอาร์เรย์แบบยาว
นอกจากนี้ ฉันยังไม่พบกลเม็ดเด็ดๆ ที่ใช้ double-splat (**
) โอเปอเรเตอร์เพื่อยุ่งกับแฮช ง่อย!
กำลังสร้างอาร์เรย์
ตัวดำเนินการ splat มีประโยชน์ไม่เพียงแต่สำหรับการทำลายอาร์เรย์แต่ยังสำหรับการสร้างพวกมันด้วย
ในตัวอย่างต่อไปนี้ เราใช้ splat เพื่อรวมสองอาร์เรย์
[*[1,2], *[3,4]]
=> [1, 2, 3, 4]
ซึ่งเทียบเท่ากับ [[1, 2], [3,4]].flatten
.
ถ้าเรื่องนั้นจบไปคงไม่มีประโยชน์อะไรมาก แต่ Splat มีความสามารถพิเศษอีกอย่างหนึ่ง มันสามารถบังคับวัตถุลงในอาร์เรย์ได้อย่างชาญฉลาด
# Usually `*thing` wraps `thing` in an array
x = *"hi mom"
# => ["hi mom"]
# ...unless it's nil
x = *nil
# => []
# Arrays are passed through unchanged
x = *[1,2,3]
# => [1, 2, 3]
# But hashes are converted to arrays
x = *{a: 1}
# => [[:a, 1]]
สิ่งนี้ทำให้เรามีเครื่องมือสำหรับการสร้างอาร์เรย์โดยไม่ต้องทำการบังคับแบบแมนนวลมากมาย
ตัวอย่างเช่น สมมติว่าคุณกำลังรวบรวมอาร์เรย์ของสตริงสำหรับระบบการกำหนดค่าบางระบบ โดยปกติคุณต้องการ:
- ตรวจสอบว่ามีอาร์เรย์อยู่หรือไม่ และเริ่มต้นอาร์เรย์หากไม่มี
- ตอบสนองอย่างชาญฉลาดหากมีคนพยายามเพิ่มอาร์เรย์ของสตริง ไม่ใช่แค่สตริงเดียว
ตัวดำเนินการ splat ให้สิ่งนี้แก่เราฟรี:
# Your configuration hash may or may not have
# an existing :ignore array.
config = { }
# The callback function might return an array
# or it might return a single item.
def add_ignores
"scoundrels" # could also be an array like ["scoundrels", "cads", "ne'er-do-wells"]
end
# This is where the magic happens. No matter what you
# start with you get an array of things to ignore.
config[:ignore] = [*config[:ignore], *add_ignores()]
แค่นี้แหละ
ฉันหวังว่าชัดเจนว่าคุณไม่ควรเขียนโค้ดการจัดการอาร์เรย์ที่มีอยู่ทั้งหมดใหม่เพื่อใช้ splats ไม่ใช่เครื่องมือที่ถูกต้องเสมอไป และอาจทำให้โค้ดอ่านยากเมื่อใช้บ่อยๆ
อย่างไรก็ตาม บางครั้งเคล็ดลับอาร์เรย์ก็เป็นสิ่งที่คุณต้องการจริงๆ ฉันหวังว่าเมื่อถึงเวลานั้น คุณจะลองทำดู :)