Вопрос

Я пытаюсь выучить немного рубина. Представьте, что я зацикливаюсь и выполняю длительный процесс, и в этом процессе я хочу получить счетчик столько, сколько потребуется.

Чтобы я мог сделать:

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}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top