什么是&。(和号)在Ruby中表示什么?


Answers:


205

它称为安全导航操作员。它在Ruby 2.3.0中引入,它使您可以在对象上调用方法,而不必担心对象可能是nil(避免undefined method for nil:NilClass错误),类似于tryRails中方法

所以你可以写

@person&.spouse&.name

代替

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

文档中

my_object.my_method

这会将my_method消息发送到my_object。任何对象都可以是接收者,但根据方法的可见性,发送消息可能会引发NoMethodError。

您可以使用&。要指定接收方,则当接收方为nil时,不会调用my_method且结果为nil。在这种情况下,不会评估my_method的参数。


13
实际上,它的工作方式类似于该try!方法,而不是try
Grzegorz

58

注意:即使@Santosh给出了清晰而完整的答案,我仍想添加更多背景知识,并添加有关其与非实例变量一起使用的重要说明


它称为“ 安全导航运算符 ”(又名“可选链接运算符”,“空条件运算符”等)。Matz似乎将其称为“孤独的运营商”。它是在Ruby 2.3引入的。它只会向对象发送方法nil

例:

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

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

带有局部变量的“边缘情况”:

请注意,以上代码使用实例变量。如果要对局部变量使用安全的导航运算符,则必须检查是否首先定义了局部变量。

# `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

要解决此问题,请检查是否首先定义了局部变量或将其设置为nil:

# 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等。但是,常见的语法是?.(问号)。但是,Ruby无法采用此语法。由于?方法名称中允许使用?.符号,因此,符号序列已经是有效的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

在选择语法时,开发人员研究了不同的极端情况,因此进行讨论非常有用。如果您想了解运算符的所有变体和细微差别,请参阅官方Ruby问题跟踪器上的此功能介绍讨论


什么是 '。?' ?我认为已决定无法使用此语法。我只能得到“&”。上班。
基思·贝内特

2
确实,正如我所写的那样.?,其他选项也被考虑了,但&.被选择了!所以,只有&.工作。
乌兹别克斯坦,2016年

哦,对不起,直到最后我才读完。但是,如果示例中的语法正确,这会更好吗?
基思·贝内特

@KeithBennett我明白你的意思了。我的第一个例子中有错字。你是对的,这一定是,&.而不是.?,我的坏。更新了我的答案。感谢您的注意!
乌兹别克斯坦,2016年

@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?return true并且str.empty?从不被调用,从而导致该puts语句被执行。但是,在第二个示例中,str&.empty?返回nilfalse,并且该puts语句从不执行。


有趣的是,尽管从技术上讲您的第一句话str.nil?是正确的(正如您所说),这意味着str.empty?实际上根本不会被调用(这就是||运算符的工作方式)。您的其余陈述是正确的。
奥利·贝内特

1
哦,好抓住。我不确定我怎么会错过。我会改正我的帖子。谢谢!
Thomas Deranek

2
的确,使用错误的逻辑会容易得多,但是您在这里检查的是不同的事物。第二行等效于str && str.empty?不为零|| 空的。安全的导航操作员仍然非常有效地用于流量控制puts "hello" unless str&.present?(仅适用于目前的方法?)
Sampson Crowley

1

它用于零检查,例如在kotlin和swift中。与对象-> Swift和Kotlin

model = car?.model

如果我们尚未在car类中定义模型值,则此模型可以为nil(Swift)或null(Kotlin)。我们使用与号代替红宝石中的问号

model = car&.model

如果使用不带&符号的car.model,并且如果model为nil,则系统无法继续运行。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.