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...

実際には、この解決策はそれ自体の利益のためには「賢すぎる」かもしれないと思いますが、Procs の考え方を理解することはとにかく役に立ちます。

于 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のスレッドは気の利いたものですが、私が望んでいたものとは異なります。そして、 Rubyが次のようにspinner classサポートされていれば、1行の増分でより良いでしょうi++GLYPHS[@i++%GLYPHS.length]

プッシュシフトを使用したMaxspinner closureは、私には少し集中的に思えますが、結果の構文は、このジェネレーターとほぼ同じです。少なくとも、それはprocが含まれているクロージャだと思います。

Chuck'swith_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)
于 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

むかしむかし、私は配列を書きました。でもただの配列ではなく、ポインタを持った配列なので、次は永遠に呼べる! 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

あなたのコードは少し裏返しになっています。:)

なぜだめですか:

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

へへ、私の上記の答えはすべて汚いです。

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