&.method 语法(安全导航运算符)在 Ruby 中如何工作?

问题描述 投票:0回答:3

我注意到如果你输入: object &,你就得到了对象。 例如:

1.class   # => Integer
1 &.class # => Integer
'hello'.then { |x| x.equal?(x &.itself) }    # => true
[1, 2, 3] &.map(&:next)    # => [2, 3, 4]

我无法找到

object &.method
的语法文档 这个语法是如何工作的?

ruby
3个回答
5
投票

这里有 2 个独立的运算符:

  1. 安全导航操作符

    &.
    - 这是 Ruby 2.3.0 中引入的安全导航操作符。如果被调用者是
    nil
    ,它基本上会返回
    nil
    ,而不是引发异常
    undefined method called for Nil class
    。例如:

    a = 1
    a.next
    # => 2
    a&.next
    # => 2
    a = nil
    a.next
    # => NoMethodError (undefined method `next' for nil:NilClass)
    a&.next
    # => nil ## No exception, returns nil
    

    您可以在此处文档

  2. 阅读更多信息
  3. 一元

    &
    :这个运算符有点复杂。它几乎相当于调用
    #to_proc
    但又不完全一样。但对于这次讨论,让我们这样思考。所以,如果你有一个 Proc,在它前面调用
    &
    就会在 Proc 上调用
    #to_proc
    并将其转换为块

    multiply_by_2 = Proc.new { |x| x * 2 }
    # => #<Proc:0x00007fb4771cf560>
    # &multiply_by_2 almost equivalent to { |x| x * 2 } but is not correct syntax
    [1, 2].map(&multiply_by_2)
    # => [2, 4]
    # equivalent to  [1, 2].map { |x| x * 2 }
    

    但是如果我们给

    &
    运算符而不是过程提供像 :abc 这样的符号,会发生什么。它会尝试在符号上调用
    #to_proc
    ,并且 ruby 已经定义了
    Symbol#to_proc
    ,大致翻译成这样:

    def to_proc
      # this will return some block like { |x| x.send(:abc) }
      lambda { |x| x.send(self) }
    end
    

    所以

    &:abc
    使用下面的变换大致翻译成这个块
    { |x| x.abc }

    &:abc =====> :abc.to_proc =====> { |x| x.send(:abc) } ====> { |x| x.abc }
    

    因此,您可以执行

    [1, 2, 3].map { |x| x.next }
    ,而不是执行
    [1, 2, 3].map(&:next)
    ,因为
    &:next
    大致相当于块
    { |x| x.next }

    请参阅 unary &(这是我在这里所写内容的主要来源)以获取更多阅读内容。


1
投票

这是 ruby 语法,& 在对象上调用 to_proc 并将结果作为块传递给方法。

镐书《Ruby 编程 1.9 和 2.0》中的解释

块可以是对象

块就像匿名方法,但是有 对他们来说比这更重要。您还可以将块转换为对象, 将其存储在变量中,传递它,然后稍后调用它的代码。 请记住我们说过,您可以将块想象成一个 传递给方法的隐式参数?嗯,你也可以做 该参数明确。如果方法定义中的最后一个参数 以 & 符号为前缀(例如 &action ),Ruby 会查找 每当调用该方法时的代码块。该代码块是 转换为 Proc 类的对象并分配给参数。 然后,您可以将该参数视为任何其他变量。这是一个 我们在一个实例方法中创建一个 Proc 对象并存储的示例 它在实例变量中。然后我们从第二个调用该过程 实例方法。

class ProcExample

  def pass_in_block(&action)
    @stored_proc = action
  end

  def use_proc(parameter)
    @stored_proc.call(parameter)
  end
end

像这样使用它

eg = ProcExample.new
eg.pass_in_block { |param| puts "The parameter is #{param}" }
eg.use_proc(99)

产生:

参数为99


0
投票

今天第一次遇到‘安全导航运营商’!

我做了一个简单的小例子来帮助我自己的理解

arr1 = ["hi"]
arr2 = nil

arr1.first
# => "hi"

arr2.first
# undefined method `first' for nil (NoMethodError)

arr1&.first # has no effect here becauase the object the method is called on isn't nil
# => "hi"

arr2&.first
# => nil <--- no error any more, just returns nil instead
© www.soinside.com 2019 - 2024. All rights reserved.