在Ruby中访问传递的块

时间:2011-09-19 11:49:24

标签: ruby block

我有一个接受块的方法,让我们在外面调用它。它又调用一个接受另一个块的方法,将其称为内部。

我想要发生的是外部调用内部,传递一个调用第一个块的新块。

这是一个具体的例子:

class Array
  def delete_if_index
    self.each_with_index { |element, i| ** A function that removes the element from the array if the block passed to delete_if_index is true }
  end
end

['a','b','c','d'].delete_if_index { |i| i.even? }
  => ['b','d']

传递给delete_if_index的块由传递给each_with_index的块调用。

这在Ruby中是否可行,更广泛地说,我们对接收它的函数中的块有多少访问权限?

3 个答案:

答案 0 :(得分:4)

您可以将块包装在另一个块中:

def outer(&block)
  if some_condition_is_true
    wrapper = lambda {
      p 'Do something crazy in this wrapper'
      block.call # original block
    }
    inner(&wrapper)
  else
    inner(&passed_block)
  end
end

def inner(&block)
  p 'inner called'
  yield
end

outer do
  p 'inside block'
  sleep 1
end

我会说打开一个现有的块并更改其内容是做错了 TM ,也许继续传递会有帮助吗?我也要警惕路过有副作用的街区;我尝试保持lambdas确定性,并采取行动,如删除方法体中的东西。在复杂的应用程序中,这可能会使调试变得更加容易。

答案 1 :(得分:1)

也许这个例子选择不当,但你的具体例子与:

相同
[1,2,3,4].reject &:even?

打开并修改一个块会让我感觉到代码味道。以一种使副作用明显的方式编写它是很困难的。

考虑到你的例子,我认为高阶函数的组合将做你想要解决的问题。

更新:正如评论中所指出的那样,它们不一样。 [1,2,3,4].reject(&:even?)查看内容,而不是索引(并返回[1,3],而不是问题中的[2,4])。下面的内容与原始示例相同,但不会有很大变化。

[1,2,3,4].each_with_index.reject {|element, index| index.even? }.map(&:first)

答案 2 :(得分:0)

所以这是我自己问题的解决方案。传入的块被隐式转换为proc,可以通过&参数语法。然后proc存在于任何嵌套块的闭包内,因为它被分配给作用域中的局部变量,并且可以被它调用:

class Array
  def delete_if_index(&proc)
    ary = []
    self.each_with_index { |a, i| ary << self[i] unless proc.call(i) }
    ary
  end
end

[0,1,2,3,4,5,6,7,8,9,10].delete_if_index {|index| index.even?}

  => [1, 3, 5, 7, 9]

这里将块转换为proc,并分配给变量proc,然后在传递给each_with_index的块中可用。