4

我正在尝试学习一些红宝石。想象一下,我正在循环并执行一个长时间运行的过程,在这个过程中,我想获得一个微调器,只要有必要。

所以我可以这样做:

a=['|','/','-','\\']
aNow=0
# ... skip setup a big loop
print a[aNow]
aNow += 1
aNow = 0 if aNow == a.length
# ... do next step of process
print "\b"

但我认为这样做会更清洁:

def spinChar
  a=['|','/','-','\\']
  a.cycle{|x| yield x}
end
# ... skip setup a big loop
print spinChar
# ... do next step of process
print "\b"

当然 spinChar 调用需要一个块。如果我给它一个块,它会无限期地挂起。

我怎样才能得到这个块的下一个产量?

4

7 回答 7

6

Rubyyield不能按照您的示例所希望的方式工作。但这可能是一个关闭的好地方:

def spinner()
  state = ['|','/','-','\\']
  return proc { state.push(state.shift)[0] }
end

spin = spinner

# start working
print spin.call
# more work
print spin.call
# etc...

在实践中,我认为这个解决方案可能太“聪明”了,但Proc无论如何理解 s 的想法可能是有用的。

于 2009-03-05T02:31:37.277 回答
5

我喜欢所有这些建议,但我在标准库中找到了生成器,我认为它更符合我想要做的事情:

spinChar=Generator.new{ |g|
  ['|','/','-','\\'].cycle{ |x|
    g.yield x
  }
}
#then
spinChar.next
#will indefinitly output the next character.

在冻结数组上使用模数进行简单array index增量似乎是最快的。

Vlad 的主题很漂亮,但不是我想要的。如果像这样spinner class支持 Ruby,单行增量会更好i++GLYPHS[@i++%GLYPHS.length]

Max's spinner closurewith push shift 对我来说似乎有点密集,但生成的语法几乎与此生成器完全相同。至少我认为这是一个带有 proc 的闭包。

Chuck'swith_spinner实际上非常接近我想要的,但是如果你不需要像上面那样的生成器,为什么要打破。

Vadim,感谢您指出这generator会很慢。

"Here's a test of 50,000 spins:"
                   user       system     total       real
"array index"      0.050000   0.000000   0.050000 (  0.055520)
"spinner class"    0.100000   0.010000   0.110000 (  0.105594)
"spinner closure"  0.080000   0.030000   0.110000 (  0.116068)
"with_spinner"     0.070000   0.030000   0.100000 (  0.095915)
"generator"        6.710000   0.320000   7.030000 (  7.304569)
于 2009-03-05T03:33:49.530 回答
5

我认为你在正确的轨道上cycle。像这样的东西怎么样:

1.8.7 :001 > spinner = ['|','/','-','\\'].cycle
 => #<Enumerable::Enumerator:0x7f111c165790> 
1.8.7 :002 > spinner.next
 => "|" 
1.8.7 :003 > spinner.next
 => "/" 
1.8.7 :004 > spinner.next
 => "-" 
1.8.7 :005 > spinner.next
 => "\\" 
1.8.7 :006 > spinner.next
 => "|" 
于 2013-02-15T12:03:41.797 回答
4

我认为您不太了解yieldRuby 中的功能。它不会从块中返回值——它会将值传递您传递给封闭方法的块。

我想你想要更像这样的东西:

def with_spinner
  a=['|','/','-','\\']
  a.cycle do |x|
    print x
    $stdout.flush # needed because standard out is usually buffered
    yield # this will call the do-block you pass to with_spinner
  end
end

with_spinner do
  #process here
  #break when done
end
于 2009-03-05T02:10:32.833 回答
0

你的代码有点由内而外,如果你能原谅我这么说的话。:)

为什么不:

class Spinner
  GLYPHS=['|','/','-','\\']
  def budge
    print "#{GLYPHS[@idx = ((@idx || 0) + 1) % GLYPHS.length]}\b"
  end
end

spinner = Spinner.new
spinner.budge
# do something
spinner.budge
spinner.budge
# do something else
spinner.budge

现在,如果你想要类似的东西:

with_spinner do
  # do my big task here
end

...那么你必须使用多线程

def with_spinner
  t = Thread.new do
    ['|','/','-','\\'].cycle { |c| print "#{c}\b" ; sleep(1) }
  end
  yield
  Thread.kill(t) # nasty but effective
end
于 2009-03-05T02:03:11.633 回答
0

曾几何时,我写了一个数组。但它不仅仅是一个数组,它是一个有指针的数组,所以你可以调用 next everrr! http://gist.github.com/55955

将这个类与一个简单的迭代器或循环配对,你就可以了。

 a = Collection.new(:a, :b, :c)
 1000.times do |i|
   puts a.current
   a.next
 end
于 2009-03-05T04:12:20.153 回答
0

呵呵,我上面的答案都是肮脏的。

a=['|','/','-','\\']
a << a
a.each {|item| puts item}
于 2012-10-13T02:50:53.140 回答