Ruby方法可以作为迭代器产生还是根据上下文返回数组?

sh-*_*eta 10 ruby arrays methods iterator return-value

我在Ruby中有一个任意方法,它产生多个值,因此可以将它传递给一个块:

def arbitrary
  yield 1
  yield 2
  yield 3
  yield 4
end

arbitrary { |x| puts x }
Run Code Online (Sandbox Code Playgroud)

我想修改这个方法,这样,如果没有块,它只是将值作为数组返回.所以这个结构也可以运行:

myarray = arbitrary
p a -----> [1, 2, 3, 4, 5]
Run Code Online (Sandbox Code Playgroud)

这可能在Ruby中吗?

Sub*_*Rao 19

def arbitrary
  values = [1,2,3,4]
  return values unless block_given? 
  values.each { |val| yield(val) }
end
arbitrary { |x| puts x }
arbitrary
Run Code Online (Sandbox Code Playgroud)


blt*_*txd 14

有一种语法:

def arbitrary(&block)
  values = [1, 2, 3, 4]
  if block
    values.each do |v|
      yield v
    end
  else
    values
  end
end
Run Code Online (Sandbox Code Playgroud)

注意:

yield v
Run Code Online (Sandbox Code Playgroud)

可以替换为:

block.call v
Run Code Online (Sandbox Code Playgroud)

  • 如果用"if block_given?"替换"if block",你甚至不必将"&block"参数显式化,并且你可以满足于"def任意".这是常见的Ruby实践. (10认同)

lev*_*lex 12

在ruby 1.9+中,您可以使用Enumerator来实现它.

def arbitrary(&block)
  Enumerator.new do |y|
    values = [1,2,3,4]
    values.each { |val| y.yield(val) }
  end.each(&block)
end
Run Code Online (Sandbox Code Playgroud)

它的优势在于它也适用于无限流:

# block-only version
#
def natural_numbers
  0.upto(1/0.0) { |x| yield x }
end

# returning an enumerator when no block is given
#
def natural_numbers(&block)
  Enumerator.new do |y|
    0.upto(1/0.0) { |x| y.yield(x) }
  end.each(&block)
end
Run Code Online (Sandbox Code Playgroud)

但最惯用的方法是用to_enum(your_method_name, your_args)这样保护你的方法:

def arbitrary
  return to_enum(:arbitrary) unless block_given?

  yield 1
  yield 2
  yield 3
  yield 4
end
Run Code Online (Sandbox Code Playgroud)

这是ruby核心库本身在多个地方使用的习惯用语.