Ze *_*Gao 3 ruby arguments argument-unpacking proc
a_proc = Proc.new {|a,b,*c| p c; c.collect {|i| i*b }}
puts a_proc[2,2,4,3]
Run Code Online (Sandbox Code Playgroud)
根据https://ruby-doc.org/core-2.2.0/Proc.html,上面的代码非常直观,a_proc [2,2,4,3]只是a_proc.call(2,2 ,4,3)隐藏“通话”
但是以下内容(效果很好)让我很困惑
a=[2,2,4,3]
puts a_proc.call(a)
puts a_proc.call(*a)
Run Code Online (Sandbox Code Playgroud)
似乎与普通的函数调用有很大不同,因为它不检查传入的数字参数。
但是,按预期方式,如果同样使用参数,则调用语义的方法将引发错误
def foo(a,b,*c)
c.collect{|i| i*b}
end
foo([1,2,3,4]) #`block in <main>': wrong number of arguments (given 1, expected 2+) (ArgumentError)
foo(*[1,2,3,4]) #works as expected
Run Code Online (Sandbox Code Playgroud)
我不认为这种不一致是设计故障,因此,对此有任何见解将不胜感激。
块使用与方法不同的语义来将参数绑定到参数。
在这方面,块语义比赋值语义更类似于赋值语义。实际上,在旧版本的Ruby中,块实际上是用于参数绑定的赋值,您可以编写如下代码:
class Foo; def bar=(val) puts 'setter called!' end end
some_proc = Proc.new {|$foo, @foo, foo.bar|}
some_proc.call(1, 2, 3)
# setter called!
$foo #=> 1
@foo #=> 2
Run Code Online (Sandbox Code Playgroud)
值得庆幸的是,自Ruby 1.9起,情况已不再如此。但是,保留了一些语义:
to_ary消息(如果Array该参数尚未存在),并且参数将绑定到参数的元素上。Arraynil注意:#1是使Hash#each工作如此精美的原因,否则,您将始终必须解构传递给块的数组。
简而言之,块参数的绑定方式与多重分配的绑定方式几乎相同。您可以想象没有赋值器,索引器,全局变量,实例变量和类变量的赋值,只有局部变量,这几乎就是块的参数绑定的工作方式:从块中复制并粘贴参数列表,从,复制并粘贴参数列表yield,放置=中间的一个标志,您就会明白。
现在,您实际上不是在谈论一个街区,而是在谈论一个Proc。对于这一点,你需要知道一些重要的事情:有两个种类的的ProcS,不幸都使用相同的类来实现。(IMO,它们应该是两个不同的类。)一种称为lambda,另一种通常称为proc(令人困惑,因为两者都是Procs)。
无论是在参数绑定和参数传递(即上述赋值语义)方面,还是在行为return(从最接近的词法包围方法返回)方面,过程的行为都像块。
无论是参数绑定和参数传递(即严格的参数检查),还是参数的行为(从lambda本身返回),Lambda的行为都与方法类似return。
一个简单的助记符:“ block”和“ proc”押韵,“ method”和“ lambda”都是希腊语。
对您的问题的一句话:
a_proc [2,2,4,3]只是a_proc.call(2,2,4,3)隐藏“调用” 的语法糖
这不是语法糖。而是Proc简单地定义与[]行为相同的方法call。
什么是语法糖:
a_proc.(2, 2, 4, 3)
Run Code Online (Sandbox Code Playgroud)
每次发生
foo.(bar, baz)
Run Code Online (Sandbox Code Playgroud)
被解释为
foo.call(bar, baz)
Run Code Online (Sandbox Code Playgroud)