我注意到如果你输入: 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
的语法文档
这个语法是如何工作的?
这里有 2 个独立的运算符:
安全导航操作符
&.
- 这是 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
一元
&
:这个运算符有点复杂。它几乎相当于调用 #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 &(这是我在这里所写内容的主要来源)以获取更多阅读内容。
这是 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
今天第一次遇到‘安全导航运营商’!
我做了一个简单的小例子来帮助我自己的理解
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