Sam*_*ami 142 ruby syntax operators parameter-passing ruby-2.3
我遇到了这行ruby代码.这&.意味着什么?
@object&.method
Run Code Online (Sandbox Code Playgroud)
San*_*osh 181
它被称为安全导航操作员.在Ruby 2.3.0中引入,它允许您调用对象上的方法而不必担心对象可能nil(避免undefined method for nil:NilClass错误),类似于tryRails中的方法.
所以你可以写
@person&.spouse&.name
Run Code Online (Sandbox Code Playgroud)
代替
@person.spouse.name if @person && @person.spouse
Run Code Online (Sandbox Code Playgroud)
来自Docs:
my_object.my_method这会将my_method消息发送到my_object.任何对象都可以是接收者,但根据方法的可见性,发送消息可能会引发NoMethodError.
你可以使用&.指定一个接收器,然后调用my_method,当接收器为零时结果为nil.在这种情况下,不评估my_method的参数.
Uzb*_*jon 54
注意:即使@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
Run Code Online (Sandbox Code Playgroud)
请注意,上面的代码使用实例变量.如果要将安全导航运算符与局部变量一起使用,则必须先检查是否已定义局部变量.
# `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
Run Code Online (Sandbox Code Playgroud)
要解决此问题,请检查是否首先定义了局部变量或将其设置为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
Run Code Online (Sandbox Code Playgroud)
Rails有try基本相同的方法.它在send内部使用方法来调用方法.Matz认为它很慢,这应该是一个内置的语言功能.
许多其他编程语言具有类似的功能:Objective C,Swift,Python,Scala,CoffeeScript等.但是,常见的语法是?.(问题点).但是,Ruby不能采用这种语法.因为?在方法名称中允许,因此?.符号序列已经是有效的Ruby代码.例如:
2.even?.class # => TrueClass
Run Code Online (Sandbox Code Playgroud)
这就是为什么Ruby社区必须提出不同的语法.这是一个积极的讨论,被认为不同的选项(.?,?,&&等等).以下列出了一些注意事项:
u.?profile.?thumbnails
u\profile\thumbnails
u!profile!thumbnails
u ? .profile ? .thumbnails
u && .profile && .thumbnails
# And finally
u&.profile&.thumbnails
Run Code Online (Sandbox Code Playgroud)
在选择语法时,开发人员会查看不同的边缘情况,讨论非常有用.如果您想了解运营商的所有变体和细微差别,请参阅官方Ruby问题跟踪器上的此功能介绍讨论.
safe navigation operator (&.):告诉 Ruby 仅在接收者\xe2\x80\x99t nil 时调用下一个方法。否则,表达式返回 nil。
实际行动
\n让\xe2\x80\x99s 构造Roster一个Sports team. 遗嘱Roster包含multiple Player对象。
class Roster\n attr_accessor :players\nend\n\nclass Player\n attr_accessor :name, :position\n \n def initialize(name, position)\n @name = name\n @position = position\n end\n\nend\nRun Code Online (Sandbox Code Playgroud)\n有了这两个对象,我们可以创建 2 对 2 女子\xe2\x80\x99s 篮球锦标赛的名单:
\nmoore = Player.new("Maya Moore", "Forward")\ntaurasi = Player.new("Diana Taurasi", "Guard")\ntourney_roster1 = Roster.new\ntourney_roster1.players = [moore, taurasi]\nRun Code Online (Sandbox Code Playgroud)\n如果我们想知道我们球队的前锋2-on-2,我们可以这样找到名字:
if tourney_roster1.players.first.position == "Forward"\n puts "Forward: #{tourney_roster1.players.first.name}"\nend\nRun Code Online (Sandbox Code Playgroud)\n\n\n但是如果我们的对手名单\xe2\x80\x99设置不正确怎么办?
\n
tourney_roster2 = Roster.new\nif tourney_roster2.players.first.position == "Forward"\n puts "Forward: #{tourney_roster1.players.first.name}"\nend\nRun Code Online (Sandbox Code Playgroud)\ntourney_roster2尚未对任何播放器设置\xe2\x80\x99。前面的代码将引发一个NoMethodError because tourney_roster2.players returns nil. 我们可以添加条件语句来避免这种情况,但这会使我们的 if 语句变得冗长且不清楚:
if tourney_roster2.players &&\n tourney_roster2.players.first &&\n tourney_roster2.players.first.position == "Forward"\nRun Code Online (Sandbox Code Playgroud)\n相反,我们可以使用安全导航运算符来避免 NoMethodError:
\nif tourney_roster2.players&.first&.position == "Forward"\n puts "Forward: #{tourney_roster1.players.first.name}"\nend\nRun Code Online (Sandbox Code Playgroud)\n因此,
\n >> tourney_roster2.players&.first == nil\n #=> true\n >> tourney_roster2.players&.first&.position == nil\n #=> true\nRun Code Online (Sandbox Code Playgroud)\n一些合法的用例:在处理多个对象时(如此处所示)以及将方法链接在一起时,安全导航运算符会派上用场。
\n警惕!尽管安全的导航操作员很方便,但也很容易欺骗自己改变逻辑。我建议避免在流量控制中使用它。例:
str = nil
puts "Hello" if str.nil? || str.empty?
# The above line is different than the below line
puts "Hello" if str&.empty?
Run Code Online (Sandbox Code Playgroud)
在第一个示例中,str.nil?return true并且str.empty?从不被调用,从而导致该puts语句被执行。但是,在第二个示例中,str&.empty?返回nilfalse,并且该puts语句从不执行。