อะไร &. (เครื่องหมายแอมเปอร์แซนด์) มีความหมายในรูบีหรือไม่


คำตอบ:


205

มันเรียกว่าผู้ประกอบการนำทางที่ปลอดภัย นำมาใช้ในทับทิม 2.3.0 จะช่วยให้คุณเรียกวิธีการบนวัตถุโดยไม่ต้องกังวลว่าวัตถุที่อาจจะnil(หลีกเลี่ยงundefined method for nil:NilClassข้อผิดพลาด) คล้ายกับวิธีการในทางรถไฟtry

ดังนั้นคุณสามารถเขียน

@person&.spouse&.name

แทน

@person.spouse.name if @person && @person.spouse

จากเอกสาร :

my_object.my_method

สิ่งนี้จะส่งข้อความ my_method ไปยัง my_object วัตถุใด ๆ ที่สามารถรับ แต่ขึ้นอยู่กับการมองเห็นวิธีการส่งข้อความอาจเพิ่ม NoMethodError

คุณสามารถใช้ &. ในการกำหนดตัวรับสัญญาณ my_method จะไม่ถูกเรียกใช้และผลลัพธ์จะเป็นศูนย์เมื่อตัวรับเป็นศูนย์ ในกรณีนั้นข้อโต้แย้งของ my_method จะไม่ได้รับการประเมิน


13
อันที่จริงมันใช้งานได้เหมือนtry!วิธีการไม่ใช่try
Grzegorz

58

หมายเหตุ: แม้ว่า @Santosh จะให้คำตอบที่ชัดเจนและครบถ้วน แต่ฉันต้องการเพิ่มพื้นหลังเพิ่มเติมและเพิ่มบันทึกย่อที่สำคัญเกี่ยวกับการใช้กับตัวแปรที่ไม่ใช่อินสแตนซ์


มันถูกเรียกว่า "ตัวดำเนินการนำทางที่ปลอดภัย " ( aka "ตัวดำเนินการผูกมัดตัวเลือก", "ตัวดำเนินการ Null แบบมีเงื่อนไข" ฯลฯ ) Matz ดูเหมือนจะเรียกมันว่า "ผู้ดำเนินการที่อ้างว้าง" มันถูกนำมาใช้ในทับทิม 2.3 nilมันจะส่งวิธีการเพื่อให้วัตถุเท่านั้นถ้ามันไม่ได้

ตัวอย่าง:

# Call method `.profile` on `user` only if `user` is not `nil`
@user&.profile

# Equivalent to
unless @user.nil?
  @user.profile
end

"Edge case" พร้อมตัวแปรโลคอล:

โปรดทราบว่ารหัสข้างต้นใช้ตัวแปรอินสแตนซ์ ถ้าคุณต้องการใช้โอเปอเรเตอร์ที่ปลอดภัยพร้อมตัวแปรโลคอลคุณจะต้องตรวจสอบว่าตัวแปรโลคอลของคุณถูกกำหนดไว้ก่อน

# `user` local variable is not defined previous
user&.profile

# This code would throw the following error:
NameError: undefined local variable or method `user' for main:Object

ในการแก้ไขปัญหานี้ให้ตรวจสอบว่าตัวแปรโลคัลของคุณถูกกำหนดไว้ก่อนหรือตั้งเป็นไม่มี:

# Option 1: Check the variable is defined
if defined?(user)
  user&.profile
end

# Option 2: Define your local variable. Example, set it to nil
user = nil
user&.profile     # Works and does not throw any errors

พื้นหลังวิธีการ

Rails มีtryวิธีการที่เหมือนกันโดยทั่วไป มันใช้sendวิธีการภายในเพื่อเรียกวิธีการภายใน Matz แนะนำว่ามันช้าและควรเป็นคุณสมบัติภาษาในตัว

ภาษาการเขียนโปรแกรมอื่น ๆ อีกมากมายมีคุณสมบัติที่คล้ายกัน: Objective C, Swift, Python, Scala, CoffeeScript ฯลฯ อย่างไรก็ตามไวยากรณ์ทั่วไปคือ?.(question dot) แต่ไวยากรณ์นี้ไม่สามารถนำมาใช้โดย Ruby เนื่องจาก?ได้รับอนุญาตในชื่อเมธอดดังนั้น?.ลำดับสัญลักษณ์จึงเป็นรหัสทับทิมที่ถูกต้อง ตัวอย่างเช่น:

2.even?.class  # => TrueClass

นั่นเป็นสาเหตุที่ชุมชน Ruby ต้องมีไวยากรณ์ที่แตกต่างกัน มันได้รับการอภิปรายที่ใช้งานและตัวเลือกที่แตกต่างกันได้รับการพิจารณา ( .?, ?, &&ฯลฯ ) นี่คือรายการของข้อควรพิจารณาบางอย่าง:

u.?profile.?thumbnails
u\profile\thumbnails
u!profile!thumbnails
u ? .profile ? .thumbnails
u && .profile && .thumbnails

# And finally
u&.profile&.thumbnails

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


คืออะไร '.?' ? ฉันคิดว่ามีการตัดสินใจแล้วว่าไม่สามารถใช้ไวยากรณ์นี้ได้ ฉันสามารถได้รับ '&.' เท่านั้น ไปทำงาน.
Keith Bennett

2
ตรงตามที่ฉันเขียน.?และตัวเลือกอื่น ๆ ได้รับการพิจารณา แต่&.เลือก! ดังนั้น&.จะทำงาน
Uzbekjon

โอ้ขอโทษฉันอ่านจนจบไม่ได้ จะดีกว่าไหมหากตัวอย่างมีไวยากรณ์ที่ถูกต้อง
Keith Bennett

@ KeithBennett ฉันเห็นว่าคุณหมายถึงอะไร ฉันพิมพ์ผิดในตัวอย่างแรกของฉัน คุณพูดถูกต้องมัน&.ไม่.?เลวเลยนะ อัปเดตคำตอบของฉัน ขอบคุณสำหรับหัวขึ้น!
Uzbekjon

@ Uzbekjon ยังมีการพิมพ์ผิดในกรณีตัวอย่างEdge (ตัวเลือก 1): user.?profileควรจะuser&.profile(ไม่สามารถแก้ไขได้ด้วยตัวเองเพราะมันเป็นเพียงการแก้ไข 1 ตัวอักษร!)
Yanis Vieilly

7

ระวังตัวด้วย! แม้ว่าผู้ให้บริการการนำทางที่ปลอดภัยนั้นสะดวก แต่มันก็ง่ายที่จะหลอกตัวเองให้เปลี่ยนตรรกะด้วย ฉันแนะนำให้หลีกเลี่ยงการใช้มันในการควบคุมการไหล ตัวอย่าง:

str = nil

puts "Hello" if str.nil? || str.empty?
# The above line is different than the below line
puts "Hello" if str&.empty?

ในตัวอย่างแรกstr.nil?ส่งคืนtrueและstr.empty?ไม่ถูกเรียกใช้ทำให้putsคำสั่งถูกเรียกใช้งาน อย่างไรก็ตามในตัวอย่างที่สองstr&.empty?ส่งคืนnilซึ่งเป็นเท็จและputsคำสั่งจะไม่ดำเนินการ


ที่น่าสนใจแม้ว่าในทางเทคนิคในคำแถลงแรกของคุณstr.nil?จะเป็นจริง (ตามที่คุณพูด) ซึ่งหมายความว่าstr.empty?จะไม่ถูกเรียก||ใช้เลย ส่วนที่เหลือของคำสั่งของคุณถูกต้อง
Ollie Bennett

1
โอ้ดีจัง ฉันไม่แน่ใจว่าฉันคิดถึงสิ่งนั้นอย่างไร ฉันจะแก้ไขโพสต์ของฉัน ขอบคุณ!
โทมัส Deranek

2
เป็นความจริงที่ว่าจะใช้ตรรกะผิดง่ายกว่ามาก แต่คุณกำลังตรวจสอบสิ่งต่าง ๆ ที่นี่ บรรทัดที่สองนั้นเทียบเท่ากับถ้า str && str.empty? ไม่เป็นศูนย์ ว่างเปล่า ผู้ประกอบการนำทางที่ปลอดภัยยังคงใช้ได้อย่างสมบูรณ์แบบที่จะใช้สำหรับการควบคุมการไหลputs "hello" unless str&.present?(ทางรถไฟเฉพาะสำหรับวิธีการปัจจุบัน)
Sampson Crowley

1

มันใช้สำหรับการตรวจสอบศูนย์เช่นใน kotlin และรวดเร็วตัวอย่างเช่น กับวัตถุ -> Swift และ Kotlin

model = car?.model

โมเดลนี้สามารถเป็นศูนย์ (Swift) หรือ null (Kotlin) หากเรายังไม่ได้กำหนดค่ารุ่นในคลาสรถยนต์ เราใช้เครื่องหมายและแทนเครื่องหมายคำถามเป็นทับทิม

model = car&.model

ถ้าใช้ car.model ที่ไม่มีเครื่องหมายและและเป็นรุ่นที่ไม่มีระบบจะไม่สามารถทำงานต่อไปได้

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