Бесконечные выходы от итератора
Вопрос
Я пытаюсь выучить немного рубина. Представьте, что я зацикливаюсь и выполняю длительный процесс, и в этом процессе я хочу получить счетчик столько, сколько потребуется.
Чтобы я мог сделать:
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 хочет получить блок. Если я дам ему блок, он будет зависать бесконечно.
Как я могу получить только следующий результат этого блока?
Решение
Ruba yield
не работает в так, как хотелось бы вашему примеру. Но это может быть хорошим местом для закрытия :
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 может быть полезен в любом случае.
Другие советы
Мне нравятся все эти предложения, но я нашел Генератор в стандартной библиотеке, и я думаю, что это больше похоже на то, что я хотел сделать:
spinChar=Generator.new{ |g|
['|','/','-','\\'].cycle{ |x|
g.yield x
}
}
#then
spinChar.next
#will indefinitly output the next character.
Обычный индекс массива
с модулем для замороженного массива выглядит наиболее быстрым.
Нить Влада изящная, но не совсем то, что я хотел. А в spinner class
приращение в одну строку было бы лучше, если бы Ruby поддерживал i ++
, например, GLYPHS [@i ++% GLYPHS.length]
Макс закрытие прядей
с push-shift мне кажется немного интенсивным, но результирующий синтаксис почти такой же, как этот генератор. По крайней мере, я думаю, что это закрытие с proc там.
<код> with_spinner Чака на самом деле довольно близок к тому, что я хотел, но зачем ломать голову, если вам не нужно использовать генератор, как указано выше.
Вадим, спасибо, что указал, что 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)
Я думаю, что вы были на правильном пути с цикла
. Как насчет такого:
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
=> "|"
Я не думаю, что вы понимаете, что yield
делает в Ruby. Он не возвращает значение из блока & # 8212; он передает значение в блок, который вы передали включающему методу.
Я думаю, вы хотите что-то более похожее на это:
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
Когда-то я написал массив. Но это не просто массив, это массив с указателем, так что вы можете вызывать next foreverrr! http://gist.github.com/55955
Соедините этот класс с простым итератором или циклом, и вы - золотой.
a = Collection.new(:a, :b, :c)
1000.times do |i|
puts a.current
a.next
end
Ваш код немного наизнанку, если вы извините, я так сказал. :) Р>
Почему бы и нет:
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
Хе-хе, мой ответ выше всего грязный.
a=['|','/','-','\\']
a << a
a.each {|item| puts item}