在Ruby中,&.(和号点)是什么意思?

qnzebej0  于 2022-11-29  发布在  Ruby
关注(0)|答案(8)|浏览(323)

我偶然发现了这行ruby代码,其中&.是什么意思?

@object&.method
dojqjjoe

dojqjjoe1#

它被称为安全导航操作符(Safe Navigation Operator),在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
您可以使用&.来指定接收者,则当接收者为nil时,不会调用my_method,结果为nil。在这种情况下,不会计算my_method的参数。

6kkfgxo0

6kkfgxo02#

  • 注意:尽管@Santosh给出了一个清晰而完整的答案,我还是想补充一些背景知识,并添加一个重要说明,关于它与非示例变量的使用。*

它被称为“Safe Navigation Operator“(*aka“可选链接运算符”、“空条件运算符”等 *)。Matz似乎称它为“孤独运算符”。它是introduced in 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 suggested,它很慢,这应该是一个内置的语言特性。
许多其他编程语言都有类似的功能: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问题跟踪器上的this feature introduction discussion

eit6fx6z

eit6fx6z3#

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

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陈述式。

vddsk6oq

vddsk6oq4#

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

**一些合理的用例:**在处理多个对象时(如此处所示),以及在将方法链接在一起时,安全导航运算符非常有用。

ukxgm1gy

ukxgm1gy5#

它用于空校验,如在Kotlin和swift中举例;对象-〉Swift和Kotlin

model = car?.model

如果我们没有在car类中定义model值,则此model可以是nil(Swift)或null(Kotlin)。我们在ruby中使用“与”号代替问号

model = car&.model

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

wqsoz72f

wqsoz72f6#

这里有一个short-read(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>`
a0x5cqrl

a0x5cqrl7#

对于从Typescript转到此处的所有用户,它与?运算符相同

wnrlj8wa

wnrlj8wa8#

ruby on rails中的object&.an_attribute是什么意思?
我是Ruby on Rails的新手,我看到了这种代码,但我不理解它:
在Ruby中,和大多数主流编程语言一样,用户代码 * 不能 * 修改编程语言的基本工作方式,也不能改变编程语言的语法。
由于Ruby on Rails只是Ruby代码,因此很明显,这不可能与Ruby on Rails有任何关系。
因此,我们需要从Ruby中寻找解释,而不是Ruby on Rails。

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 Syntax documentation
&.,称为“安全导航运算符”,允许在接收方为nil时跳过方法调用。如果跳过调用,它将返回nil,并且不计算方法的参数。

相关问题