ChatGPT解决这个技术问题 Extra ChatGPT

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

我遇到了这行 ruby 代码。 &. 是什么意思?

@object&.method

s
svelandiag

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

所以你可以写

@person&.spouse&.name

代替

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

Docs

my_object.my_method 这会将 my_method 消息发送到 my_object。任何对象都可以是接收者,但根据发送消息的方法的可见性,可能会引发 NoMethodError。您可以使用 &。指定接收者,则不调用 my_method 并且当接收者为 nil 时结果为 nil。在这种情况下,不会评估 my_method 的参数。


实际上,它的工作方式类似于 try! 方法,而不是 try
哇。我不知道我是怎么错过的,但 rubocop 只是自动更正了我的代码,以便在这数十次中使用。甚至不知道它的存在。很酷。
B
Batkins

注意:尽管@Santosh 给出了明确而完整的答案,但我想添加更多背景知识并添加关于其与非实例变量一起使用的重要说明。

它被称为“Safe Navigation Operator”(又名“可选链运算符”、“空条件运算符”等)。 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


u
user664833

警惕!尽管安全导航操作符很方便,但它也可以很容易地欺骗自己改变逻辑。我建议避免在流量控制中使用它。例子:

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 语句。


G
Gupta

safe navigation operator (&.): 告诉 Ruby 仅在接收者不为 nil 时才调用 next 方法。否则,表达式返回 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

一些合法的用例:安全导航操作符在处理多个对象(如此处所示)以及将方法链接在一起时会派上用场。


U
Umut ADALI

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

model = car?.model

如果我们没有在 car 类中定义模型值,这个模型可以是 nil(Swift) 或 null(Kotlin)。我们在 ruby 中使用 & 号而不是问号

model = car&.model

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


J
Jörg W Mittag

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 中指定,特别是 here

上下文“当上下文为零时”执行“总是返回 nil”执行 eval("nil&.unknown").should == nil eval("[][10]&.unknown").should == nil 结束它“可以被束缚” do eval("nil&.one&.two&.three").should == nil end 它“不评估参数” do obj = Object.new obj.should_not_receive(:m) eval("nil&.unknown( obj.m) { obj.m }") 结束结束

它记录在 Ruby Syntax documentationCalling Methods section 中:

&.,称为“安全导航运算符”,允许在接收者为 nil 时跳过方法调用。如果跳过调用,它返回 nil 并且不评估方法的参数。


G
G.O.

这是我在此找到的short-read(3 分钟) - 非常好。

此外,它的作用类似于 Rails 中的 try! 方法,而不是 try 方法。

因为如果接收者不是 nil 并且 not 实现了尝试的方法,它将引发 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>`