什么&。(&点)在Ruby中是什么意思?

我偶然发现了这行ruby代码。&.在这里是什么意思?

@object&.method
93051 次浏览

它被称为安全导航操作员。在Ruby 2.3.0中引入,它允许你在对象上调用方法,而不用担心对象可能是nil(避免undefined method for nil:NilClass错误),类似于Rails中的try方法

所以你可以写

@person&.spouse&.name

而不是

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

文档:

my_object.my_method

my_method消息发送到my_object。任何 对象可以是接收器,但这取决于方法的可见性 发送消息可能会引发NoMethodError.

. 0 你可以使用&.来指定接收者,那么my_method将不会被调用 并且当接收者为nil时,结果为nil。在这种情况下, my_method的实参不会被求值

注:尽管@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问题跟踪器上的本特性介绍讨论

小心!虽然安全导航操作符很方便,但也很容易欺骗自己用它改变逻辑。我建议避免在流量控制中使用它。例子:

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语句永远不会执行。

它用于nil检查,如在kotlin和swift 例如; with Object -> Swift and Kotlin

model = car?.model
如果我们没有在car类中定义模型值,这个模型可以是nil(Swift)或null(Kotlin)。 我们在ruby

中使用&号而不是问号
model = car&.model

如果使用汽车。模型没有&号,如果模型为空,系统不能继续运行。

safe navigation operator (&.):告诉Ruby只有在接收器不是nil时才调用下一个方法。否则,表达式返回nil。


实际行动

让我们为Sports team构造一个Roster对象。Roster将包含multiple Player对象。

class Roster
attr_accessor :players
end


class Player
attr_accessor :name, :position
  

def initialize(name, position)
@name = name
@position = position
end


end

有了这两个对象,我们可以创建一个2对2女子篮球锦标赛的花名册:

moore = Player.new("Maya Moore", "Forward")
taurasi = Player.new("Diana Taurasi", "Guard")
tourney_roster1 = Roster.new
tourney_roster1.players = [moore, taurasi]

如果我们想知道2-on-2团队的前进方向,我们可能会这样找到名称:

if tourney_roster1.players.first.position == "Forward"
puts "Forward: #{tourney_roster1.players.first.name}"
end

但如果我们的对手阵容设置不正确呢?

tourney_roster2 = Roster.new
if tourney_roster2.players.first.position == "Forward"
puts "Forward: #{tourney_roster1.players.first.name}"
end

tourney_roster2尚未与任何玩家设置。上面的代码将引发NoMethodError because tourney_roster2.players returns nil。我们可以添加条件语句来避免这种情况,但这会使if语句冗长且不清楚:

if tourney_roster2.players &&
tourney_roster2.players.first &&
tourney_roster2.players.first.position == "Forward"

相反,我们可以使用安全导航操作符来避免NoMethodError:

if tourney_roster2.players&.first&.position == "Forward"
puts "Forward: #{tourney_roster1.players.first.name}"
end

因此,

 >> tourney_roster2.players&.first == nil
#=> true
>> tourney_roster2.players&.first&.position == nil
#=> true

一些合法的用例:安全导航操作符在处理多个对象时很方便,如这里所示,以及在将方法链接在一起时。

在ruby on rails中object&.an_attribute是什么意思?

我是Ruby on rails的新手,我看到了这种代码,但我不理解它:

在Ruby中,像在大多数主流编程语言中一样,用户代码不能修改编程语言的基本工作方式,也不能改变编程语言的语法。

因为Ruby on Rails只是Ruby代码,所以很明显这与Ruby on Rails没有任何关系。

因此,我们需要从Ruby中寻找解释,而不是Ruby on Rails。

安全航行操作员安全的导航器ruby/speclanguage/safe_navigator_spec.rb中指定,特别是在这里:

context "when context is nil" do
it "always returns nil" do
eval("nil&.unknown").should == nil
eval("[][10]&.unknown").should == nil
end


it "can be chained" do
eval("nil&.one&.two&.three").should == nil
end


it "doesn't evaluate arguments" do
obj = Object.new
obj.should_not_receive(:m)
eval("nil&.unknown(obj.m) { obj.m }")
end
end

它被记录在Ruby语法文档呼叫方法 section中:

&.,称为“安全导航操作符”,允许在接收器为nil时跳过方法调用。它返回nil,如果跳过调用,则不计算方法的参数。

这是一个短内容(3分钟),我发现这是相当好的。

为了补充以上内容,它的作用类似于Rails中的try!方法,而不是try方法。

因为如果接收者不是nil并且实现了尝试的方法,它将引发NoMethodError异常。

摘自上述文章的例子:

account = Account.new(owner: Object.new)


account&.owner&.address
# => NoMethodError: undefined method `address' for #<Object:0x00559996b5bde8>`


account.try(:owner).try(:address)
# => nil


account.try!(:owner).try!(:address)
# => NoMethodError: undefined method `address' for #<Object:0x00559996b5bde8>`

对于那些从Typescript学来的人来说,它和?操作符是一样的