yield to an anonymous block 两个函数
yield to an anonymous block two functions up
可能有一种简单的方法可以做到这一点。
我正在尝试重构如下内容
def foo(baz)
baz.update_first
if baz.has_condition?
yield baz.val if block_given?
baz.a
else
baz.b
end
end
叫得像
foo(baz) {|b| b.modify}
类似于
def foo(baz)
baz.update_first
bar(baz) {|i| yield i if block_given? }
end
def bar(baz)
if baz.has_condition?
yield baz.val if block_given?
baz.a
else
baz.b
end
end
这行得通吗?怎么样?
我认为它会,但我希望能清楚地解释块内的屈服是如何工作的……通读 proc.c 和 vm.c 以及 relevant git commit in the ruby source code ,我认为当在 foo 中调用 bar 时,它会执行直到它产生,然后你沿着帧堆栈向上移动到 foo 中定义的块的本地环境指针,它被调用,yield 走到块 foo 被调用,执行它,然后你又回到了酒吧。那是对的吗?有更好的方法吗?
这对我来说感觉有点奇怪,就像反转控制一样,它需要 foo 比我想要的更多地了解 baz,但不幸的是我不能简单地在此代码中传递 proc 或 lambda。
我认为如果您查看另一种语法,即将 bloc 转换为 proc 参数,yield
的概念可能会更加清晰。
比如下面的例子都是一样的
def my_each(arr)
arr.each { |x| yield x }
end
def my_each(arr, &blk)
arr.each { |x| blk.call(x) }
end
# Both are called the same way
my_each([1,2,3]) { |x| print x }
# => 123
使用yield
时,变量在方法中可用,无需在参数列表中声明。在参数前加上 &
符号会将其转换为过程,因此在方法中它可以是 运行 和 .call
.
这是一个为一种方法提供块然后在以下两个范围内执行它的示例:
def method_a(number, &blk)
method_b do
method_c do
blk.call(number)
end
end
end
def method_b(&blk)
blk.call
end
def method_c(&blk)
blk.call
end
method_a(1) { |num| puts num + 1 }
# => 2
请注意 blk
不是一个神奇的词 - 您可以随意命名变量。
这与 yield 相同:
def method_a(number)
method_b do
method_c do
yield number
end
end
end
def method_b
yield
end
def method_c
yield
end
method_a(1) { |num| puts num + 1 }
# => 2
我认为使用 &blk
语法更清晰,因为它为 proc 分配了一个变量。仅仅因为方法中使用了 proc 并不意味着您必须 运行 Proc.new
。该块会自动转换为过程。
可能有一种简单的方法可以做到这一点。
我正在尝试重构如下内容
def foo(baz)
baz.update_first
if baz.has_condition?
yield baz.val if block_given?
baz.a
else
baz.b
end
end
叫得像
foo(baz) {|b| b.modify}
类似于
def foo(baz)
baz.update_first
bar(baz) {|i| yield i if block_given? }
end
def bar(baz)
if baz.has_condition?
yield baz.val if block_given?
baz.a
else
baz.b
end
end
这行得通吗?怎么样?
我认为它会,但我希望能清楚地解释块内的屈服是如何工作的……通读 proc.c 和 vm.c 以及 relevant git commit in the ruby source code ,我认为当在 foo 中调用 bar 时,它会执行直到它产生,然后你沿着帧堆栈向上移动到 foo 中定义的块的本地环境指针,它被调用,yield 走到块 foo 被调用,执行它,然后你又回到了酒吧。那是对的吗?有更好的方法吗?
这对我来说感觉有点奇怪,就像反转控制一样,它需要 foo 比我想要的更多地了解 baz,但不幸的是我不能简单地在此代码中传递 proc 或 lambda。
我认为如果您查看另一种语法,即将 bloc 转换为 proc 参数,yield
的概念可能会更加清晰。
比如下面的例子都是一样的
def my_each(arr)
arr.each { |x| yield x }
end
def my_each(arr, &blk)
arr.each { |x| blk.call(x) }
end
# Both are called the same way
my_each([1,2,3]) { |x| print x }
# => 123
使用yield
时,变量在方法中可用,无需在参数列表中声明。在参数前加上 &
符号会将其转换为过程,因此在方法中它可以是 运行 和 .call
.
这是一个为一种方法提供块然后在以下两个范围内执行它的示例:
def method_a(number, &blk)
method_b do
method_c do
blk.call(number)
end
end
end
def method_b(&blk)
blk.call
end
def method_c(&blk)
blk.call
end
method_a(1) { |num| puts num + 1 }
# => 2
请注意 blk
不是一个神奇的词 - 您可以随意命名变量。
这与 yield 相同:
def method_a(number)
method_b do
method_c do
yield number
end
end
end
def method_b
yield
end
def method_c
yield
end
method_a(1) { |num| puts num + 1 }
# => 2
我认为使用 &blk
语法更清晰,因为它为 proc 分配了一个变量。仅仅因为方法中使用了 proc 并不意味着您必须 运行 Proc.new
。该块会自动转换为过程。