ruby-on-rails - yield to an anonymous block 两个函数

标签 ruby-on-rails ruby yield

可能有一种简单的方法可以做到这一点。

我正在尝试重构如下内容

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

那行得通吗?怎么办?

我认为它会,但我希望能清楚地解释 block 内的屈服是如何工作的……通读 proc.c 和 vm.c 以及 relevant git commit in the ruby source code ,我认为当在 foo 中调用 bar 时,它会执行直到它产生,然后你将帧堆栈向上移动到 foo 中定义的 block 的本地环境指针,它被调用,其中 yield 向上移动到 block 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 时,变量在方法中可用,无需在参数列表中声明。在参数前加上 & 符号会将其转换为 proc,因此在方法中可以使用 .call 运行它。

这是一个为一个方法提供 block 然后在两个范围内执行它的示例:

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。该 block 会自动转换为过程。

关于ruby-on-rails - yield to an anonymous block 两个函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38256272/

相关文章:

javascript - 为什么yield不能解析promise?

ruby-on-rails - Webmock:如何伪造 gzipped 响应?

Ruby 将一个数组组合成一个字符串

ruby-on-rails - Ruby gsub 不替换换行符

ruby - 获取特定索引 nokogiri 中的元素

ruby-on-rails - Mac OSX Lion Apache + RubyOnRails + mod_passenger

c# - 为什么要使用 yield 关键字,而我只能使用普通的 IEnumerable?

Ruby:不允许在 'yield' 之后放置空格

ruby-on-rails - 如何从 Rails 控制台注销设计用户?

ruby-on-rails - Rails 应用程序可以处理多少并发上传