【问题标题】:yield to an anonymous block two functions up让出一个匿名块两个函数
【发布时间】:2016-11-10 09:49:55
【问题描述】:

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

我正在尝试重构如下内容

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 ,我认为当 bar 在 foo 中被调用时执行直到它产生,然后你将帧堆栈向上移动到 foo 中定义的块的本地环境指针,这被调用,其中 yield 走到块 foo 被调用,执行它,然后你回到酒吧。那是对的吗?有没有更好的方法来做到这一点?

这对我来说有点奇怪,就像反转控制一样,它需要 foo 比我想要的更多地了解 baz,但不幸的是我不能简单地在这段代码中传递一个 proc 或 lambda。

【问题讨论】:

    标签: ruby-on-rails ruby yield


    【解决方案1】:

    我认为,如果您查看另一种语法,即将 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 运行。

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

    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 不是一个神奇的词——您可以随意命名变量。

    这与产量相同:

    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。该块会自动转换为 proc。

    【讨论】:

      猜你喜欢
      • 2019-06-19
      • 2017-10-13
      • 1970-01-01
      • 2018-11-14
      • 2022-11-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多