gpt4 book ai didi

ruby - ruby 如何解压传递给 Proc 的参数?

转载 作者:数据小太阳 更新时间:2023-10-29 07:47:28 25 4
gpt4 key购买 nike

a_proc = Proc.new {|a,b,*c| p c; c.collect {|i| i*b }}
puts a_proc[2,2,4,3]

根据 https://ruby-doc.org/core-2.2.0/Proc.html,上面的代码非常直观, a_proc[2,2,4,3] 只是a_proc.call(2,2,4,3)隐藏“call”的语法糖p>

但是以下(效果很好)让我很困惑

a=[2,2,4,3]
puts a_proc.call(a)
puts a_proc.call(*a)

这似乎与普通函数调用有很大不同,因为它不检查传入的数字参数。

但是,正如预期的那样,如果同样使用参数,方法调用语义将引发错误

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

我不认为这种不一致是设计故障,所以任何对此的见解都将不胜感激。

最佳答案

block 使用与将参数绑定(bind)到参数的方法不同的语义。

在这方面, block 语义更类似于赋值语义而不是方法语义。事实上,在旧版本的 Ruby 中, block literally 使用赋值来进行参数绑定(bind),你可以这样写:

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

值得庆幸的是,自 Ruby 1.9 以来,情况已不再如此。但是,保留了一些语义:

  • 如果一个 block 有多个参数但只接收一个参数,参数将被发送一个 to_ary 消息(如果它不是一个 Array 已经)并且参数将被绑定(bind)到 Array 的元素
  • 如果一个 block 收到的参数多于它的参数,它会忽略额外的参数
  • 如果一个 block 接收的参数少于它的参数,额外的参数将绑定(bind)到 nil

注意:#1 是让 Hash#each 如此完美地工作的原因,否则,您总是必须解构它传递给 block 的数组。

简而言之, block 参数的绑定(bind)方式与多重赋值非常相似。您可以想象没有 setter 、索引器、全局变量、实例变量和类变量的赋值,只有局部变量,这几乎就是 block 参数绑定(bind)的工作方式:从 block 中复制并粘贴参数列表,从 yield 复制并粘贴参数列表,在中间放一个 = 符号,你就明白了。

现在,您实际上并不是在谈论 block ,而是在谈论 Proc 。为此,您需要知道一些重要的事情:两种 Proc s,不幸的是它们是使用同一个类实现的。 (IMO,它们应该是两个不同的类。)一种称为 lambda,另一种通常称为 proc(容易混淆,因为两者都是 Proc s) .

Procs 的行为就像 block ,无论是涉及参数绑定(bind)和参数传递(即上述赋值语义)还是涉及 return 的行为(它从最接近的词法封闭方法返回)。

Lambda 的行为类似于方法,无论是涉及参数绑定(bind)和参数传递(即严格的参数检查)还是涉及 return 的行为(它从 lambda 本身返回)。

一个简单的助记符:“block”和“proc”押韵,“method”和“lambda”都是希腊语。


对你的问题的一个小评论:

a_proc[2,2,4,3] is just a syntax sugar for a_proc.call(2,2,4,3) to hide “call”

不是语法糖。相反,Proc 只是将 [] 方法定义为与 call 行为相同。

是什么语法糖是这样的:

a_proc.(2, 2, 4, 3)

每次出现

foo.(bar, baz)

被解释为

foo.call(bar, baz)

关于ruby - ruby 如何解压传递给 Proc 的参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45388282/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com