Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

การใช้ splats เพื่อสร้างและแยกอาร์เรย์ใน Ruby

สิ่งหนึ่งที่ฉันชอบเกี่ยวกับ 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 ไม่ใช่เครื่องมือที่ถูกต้องเสมอไป และอาจทำให้โค้ดอ่านยากเมื่อใช้บ่อยๆ

อย่างไรก็ตาม บางครั้งเคล็ดลับอาร์เรย์ก็เป็นสิ่งที่คุณต้องการจริงๆ ฉันหวังว่าเมื่อถึงเวลานั้น คุณจะลองทำดู :)