English 中文(简体)
如何将Ruby迭代器作为参数传递?
原标题:how to pass a Ruby iterator as a parameter?

我想写一个在一个地方产生值的方法,并将其作为参数传递给另一个方法,该方法将用块调用它。我确信这是可以做到的,但不知怎么的,我找不到正确的语法。

下面是一些示例(非工作)代码来说明我试图实现的目标:

def yielder
  yield 1
  yield 2
  yield 3
end

def user(block)
  block.call { |x| puts x }
end

# later...
user(&yielder)

$ ruby x.rb
x.rb:2:in `yielder : no block given (yield) (LocalJumpError)
from x.rb:12:in `<main> 

FWIW,在我的真实代码中,yielder和user属于不同的类。


更新

谢谢你的回答。正如Andrew Grimm提到的,我希望迭代器方法采用参数。我最初的例子省略了这个细节。这个代码段提供了一个迭代器,该迭代器计数到给定的数字。为了使它发挥作用,我明确了内部块。它做了我想做的事,但有点难看。如果有人能在这方面有所改进,我会很有兴趣看看如何改进。

def make_iter(upto)
  def iter(upto, block)
    (1 .. upto).each do |v|
      block.call(v)
    end
  end
  lambda { |block| iter(upto, block) }
end

def user(obj)
  obj.call Proc.new { |x| puts x }
end

# later...
user(make_iter(3))
问题回答

这不使用lambda或unbound方法,但这是最简单的方法。。。

def f
  yield 1
  yield 2
end

def g x
  send x do |n|
    p n
  end
end

g :f

当你写&;yielder,您正在调用yielder,然后尝试应用&(转换为Proc)运算符。当然,在没有块的情况下调用<code>yielder</code>是不可能的。您想要的是获得对方法本身的引用。只需将该行更改为user(方法:yielder),它就可以工作了。

我认为这可能是你想要做的事情:

def yielder
  yield 1
  yield 2
  yield 3
end

def user(meth)
  meth.call { |x| puts x }
end

# later...
user( Object.method(:yielder) )

此处提供一些相关信息:http://blog.sidu.in/2007/11/ruby-blocks-gotchas.html

正如已经指出的那样,基线问题是,当您试图将函数作为参数传递时,Ruby会执行它——这是括号可选的副作用。

我喜欢前面提到的符号方法的简单性,但我担心我将来会忘记,需要将迭代器作为符号来传递才能使其工作。由于可读性是一个所需的特性,因此可以将迭代器封装到一个对象中,这样就可以传递对象,而不用担心代码被意外执行。

作为迭代器的匿名对象

也就是说:使用一个只有一个函数的匿名对象作为迭代器。阅读和理解起来很直接。但是,由于Ruby处理范围的方式受到限制,迭代器无法轻松接收参数:在函数<code>迭代器</code>中接收的任何参数在<code>每个</code〕中都不自动可用。

def iterator
    def each
        yield("Value 1")
        yield("Value 2")
        yield("Value 3")
    end
end

def iterate(my_iterator)
    my_iterator.each do |value|
        puts value
    end
end

iterate iterator

将对象作为迭代器处理

使用Proc对象作为迭代器,可以轻松使用传递给迭代器构造函数的任何变量。黑暗面:这开始看起来很奇怪。阅读Proc.new块对于未经训练的眼睛来说不是立即的。此外:不能使用<code>yield</code>会使IMHO变得更丑陋。

def iterator(prefix:)
    Proc.new { |&block|
        block.call("#{prefix} Value 1")
        block.call("#{prefix} Value 2")
        block.call("#{prefix} Value 3")
    }
end

def iterate(my_iterator)
    my_iterator.call do |value|
        puts value
    end
end

iterate iterator(prefix:  The )

Lambda作为迭代器

如果你想把你的代码弄得如此模糊,以至于除了你之外没有人能阅读它,这是理想的选择。

def iterator(prefix:)
    -> (&block) {
        block.call("#{prefix} Value 1")
        block.call("#{prefix} Value 2")
        block.call("#{prefix} Value 3")
    }
end

def iterate(my_iterator)
    my_iterator.call do |value|
        puts value
    end
end

iterate iterator(prefix:  The )

类为迭代器

最后是好的面向对象方法。根据我的口味,初始化有点冗长,但几乎没有意外效果。

class Iterator
    def initialize(prefix:)
        @prefix = prefix
    end

    def each
        yield("#{@prefix} Value 1")
        yield("#{@prefix} Value 2")
        yield("#{@prefix} Value 3")
    end
end

def iterate(my_iterator)
    my_iterator.each do |value|
        puts value
    end
end

iterate Iterator.new(prefix:  The )




相关问题
Ruby parser in Java

The project I m doing is written in Java and parsers source code files. (Java src up to now). Now I d like to enable parsing Ruby code as well. Therefore I am looking for a parser in Java that parses ...

rails collection_select vs. select

collection_select and select Rails helpers: Which one should I use? I can t see a difference in both ways. Both helpers take a collection and generates options tags inside a select tag. Is there a ...

RubyCAS-Client question: Rails

I ve installed RubyCAS-Client version 2.1.0 as a plugin within a rails app. It s working, but I d like to remove the ?ticket= in the url. Is this possible?

Ordering a hash to xml: Rails

I m building an xml document from a hash. The xml attributes need to be in order. How can this be accomplished? hash.to_xml

multiple ruby extension modules under one directory

Can sources for discrete ruby extension modules live in the same directory, controlled by the same extconf.rb script? Background: I ve a project with two extension modules, foo.so and bar.so which ...

Text Editor for Ruby-on-Rails

guys which text editor is good for Rubyonrails? i m using Windows and i was using E-Texteditor but its not free n its expired now can anyone plese tell me any free texteditor? n which one is best an ...