Unendliche Erträge aus einem Iterator
Frage
Ich versuche, einige Rubine zu lernen. Stellen Sie sich vor mir Looping und einen langen laufenden Prozess zu tun, und in diesem Prozess mag ich so lange wie notwendig, um einen Spinner erhalten.
So konnte ich tun:
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"
Aber ich dachte, es sauberer sein würde zu tun:
def spinChar
a=['|','/','-','\\']
a.cycle{|x| yield x}
end
# ... skip setup a big loop
print spinChar
# ... do next step of process
print "\b"
Natürlich will der spinChar Anruf einen Block. Wenn ich ihm einen Block geben werde es hängt auf unbestimmte Zeit.
Wie kann ich nur die nächste yeild dieses Blocks bekommen?
Lösung
yield
funktioniert nicht in der Art und Weise würde Ihr Beispiel mögen. Aber dies könnte ein guter Ort für ein Schließung sein:
def spinner()
state = ['|','/','-','\\']
return proc { state.push(state.shift)[0] }
end
spin = spinner
# start working
print spin.call
# more work
print spin.call
# etc...
In der Praxis denke ich, diese Lösung könnte auch sein, „klug“ für seine eigenen gut, aber das Verständnis der Idee von Proc
s irgendwie nützlich sein könnte.
Andere Tipps
Ich mag all diese Vorschläge, aber ich den Generator in der Standard-Bibliothek gefunden, und ich denke, es ist mehr entlang der Linien von dem, was ich tun wollte:
spinChar=Generator.new{ |g|
['|','/','-','\\'].cycle{ |x|
g.yield x
}
}
#then
spinChar.next
#will indefinitly output the next character.
Plain array index
Schritte mit einem Modul auf einem gefrorenen Array scheinen am schnellsten zu sein.
Vlads Thread ist geschickt, aber nicht genau das, was ich wollte. Und in spinner class
der einzeiligen Zuwachs wäre schöner, wenn Ruby-i++
wie GLYPHS[@i++%GLYPHS.length]
unterstützt
Max spinner closure
mit Push-Verschiebung scheint ein wenig intensiver zu mir, aber die resultierenden Syntax ist fast genau wie dieser Generator. Zumindest glaube ich, dass ein Verschluss mit proc drin.
Chucks with_spinner
ist eigentlich ziemlich nahe, was ich wollte, aber warum brechen, wenn Sie wie oben mit einem Generator nicht haben.
Vadim, Dank für den Hinweis der generator
würde langsam sein.
"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)
Ich glaube, Sie auf dem richtigen Weg mit cycle
sind. Wie wäre es so etwas wie folgt aus:
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
=> "|"
Ich glaube nicht, dass Sie ganz verstehen, was yield
in Ruby tut. Es gibt keinen Wert aus einem Block zurückkehren -. Es geht Wert der Block, den Sie die umschließende Methode übergeben haben
Ich glaube, Sie etwas mehr wollen wie folgen aus:
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
Es war einmal, schrieb ich ein Array. Aber es ist nicht nur ein Array, es ist ein Array, das einen Zeiger hat, so können Sie neben foreverrr anrufen! http://gist.github.com/55955
Paar dieser Klasse mit einem einfachen Iterator oder Schleife und Sie sind golden.
a = Collection.new(:a, :b, :c)
1000.times do |i|
puts a.current
a.next
end
Der Code ist ein bisschen von innen nach außen, wenn Sie mir verzeihen werde so sagen. :)
Warum nicht:
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
Jetzt , wenn Sie so etwas wie:
with_spinner do
# do my big task here
end
... dann müssen Sie auf Multi-Threading :
def with_spinner
t = Thread.new do
['|','/','-','\\'].cycle { |c| print "#{c}\b" ; sleep(1) }
end
yield
Thread.kill(t) # nasty but effective
end
hehe, die Antwort über mir ist alles schmutzig.
a=['|','/','-','\\']
a << a
a.each {|item| puts item}