一元与号运算符并将过程作为 Ruby 中的参数传递 [英] Unary Ampersand Operator and passing procs as arguments in Ruby
问题描述
我无法理解下面的代码.
I'm having trouble understanding this code below.
我了解到一元与号运算符并将过程作为参数传递给方法的想法.但我真的无法将self
传递给language.call
.我是这样理解的:我们将 self
作为参数传递给 proc/block 语言.这对我来说没有任何意义.有人可以解释一下吗?:)
I get the idea of Unary Ampersand Operator and passing procs as arguments to methods. But I really can't wrap my head around passing self
to the language.call
. I understand it like this: we're passing self
as an argument to the proc/block language. It doesn't make any sense to me. Can someone please explain? :)
class Translator
def speak &language
language.call(self)
end
protected
def french
'bon jour'
end
def spanish
'hola'
end
def turkey
'gobble'
end
def method_missing(*args)
'awkward silence'
end
end
我们将其用于:
translator.speak(&:spanish)
推荐答案
这个例子很好地将多个 Ruby 概念联系在一起.正因为如此,我将尝试解释所有这些.
This example beautifully ties together multiple Ruby concepts. Because of that, I will try to explain all of them.
- 块
Ruby 中的方法可以优雅地接受块(代码段):
Methods in Ruby can accept blocks (pieces of code) in elegant matter:
def run_code
yield
end
run_code { puts 42 } # => prints 42
- Proc 类似于块,但它们是实际的可寻址对象:
deep_thought = proc { puts 42 }
deep_thought.call # => prints 42
- 在使用
&
运算符调用方法时,您可以将 proc 转换为块:
- You can turn a proc into a block when calling a method with the
&
operator:
def run_code
yield
end
deep_thought = proc { puts 42 }
run_code(&deep_thought) # => prints 42
- 过程和块可以接受参数:
def reveal_answer
yield 5_000
end
deep_thought = proc do |years_elapsed|
years_elapsed >= 7_500_000 ? 42 : 'Still processing'
end
reveal_answer(&deep_thought) # => 'Still processing'
- 您可以在方法签名中使用
&
将块转换为 proc:
- You can turn a block into proc using
&
in the method signature:
def inspector(&block)
puts block.is_a?(Proc)
puts block.call
end
inspector { puts 42 } # => prints true and 42
inspector(&proc { puts 42 }) # => the same
Symbol#to_proc
创建一个调用对象上同名方法的过程:
Symbol#to_proc
creates a proc that calls methods with the same name on the object:
class Dummy
def talk
'wooooot'
end
end
:talk.to_proc.call(Dummy.new) # => "wooooot"
换句话说,
:bar.to_proc.call(foo)
几乎等同于
foo.bar
BasicObject#method_missing
:
当您尝试调用对象上的方法时,Ruby 会遍历它的祖先链,搜索具有该名称的方法.如何构建链是一个不同的主题,足够长的另一天,重要的是如果直到最底部(BasicObject
)都没有找到该方法,则对相同的方法执行第二次搜索链 - 这次是一个名为 method_missing
的方法.它作为参数传递原始方法的名称加上它收到的任何参数:
When you try to call a method on an object, Ruby traverses it's ancestor chain, searching for a method with that name. How the chain is constructed is a different topic, lengthy enough for another day, the important thing is that if the method is not found til the very bottom (BasicObject
), a second search is performed on the same chain - this time for a method called method_missing
. It gets passed as arguments the name of the original method plus any argument it received:
class MindlessParrot
def method_missing(method_name, *args)
"You caldt #{method_name} with #{args} on me, argh!"
end
end
MindlessParrot.new.foo # => "You caldt foo with [] on me, argh!"
MindlessParrot.new.bar :baz, 42 # => "You caldt bar with [:baz, 42] on me, argh!"
<小时>
那么在我们的具体案例中,这一切意味着什么?让我们假设一秒钟没有 protected
.
So what does all this mean in our specific case? Lets assume for a second there was no protected
.
translator.speak(&:spanish)
调用方法 Translator#speak
并将 :spanish
转换为块.Translator#speak
接受该块并将其转换为名为 language
的过程,并调用它,将 self
作为参数传递.self
是 Translator
的一个实例,因此,它有方法 speak
, french
, spanish
、turkey
和 method_missing
.
所以:
calls the method Translator#speak
with :spanish
converted to block.
Translator#speak
takes that block and transforms it to a proc, named language
, and calls it, passing self
as argument.
self
is an instance of Translator
, therefore, it has the methods speak
, french
, spanish
, turkey
and method_missing
.
And so:
Translator.new.speak(&:spanish)
相当于:
:spanish.to_proc.call(Translator.new)
相当于:
Translator.new.spanish
给我们hola"
.
现在,把protected
拿回来,我们translator
对象的所有语言方法都还存在,但它们不能被外人直接访问.
就像你不能打电话
Now, taking the protected
back, all the language methods of our translator
object are still present, but they can not be directly accessed by outsiders.
Just as you can't call
Translator.new.spanish
并期待 "hola"
回来,你不能打电话
and expect "hola"
back, you can't call
Translator.new.speak(&:spanish)
并且由于该方法不可直接访问,因此将其视为未找到并调用 method_missing
,从而使我们尴尬的沉默"
.
这篇关于一元与号运算符并将过程作为 Ruby 中的参数传递的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!