質問
このコードを使用して、ユーザーが名前を入力できるようにし、プログラムは空の文字列を入力するまでそれらを配列に保存します (名前を入力するたびに Enter キーを押す必要があります)。
people = []
info = 'a' # must fill variable with something, otherwise loop won't execute
while not info.empty?
info = gets.chomp
people += [Person.new(info)] if not info.empty?
end
このコードは、実行するとより見栄えがよくなります...while ループ:
people = []
do
info = gets.chomp
people += [Person.new(info)] if not info.empty?
while not info.empty?
このコードでは、ランダムな文字列に情報を割り当てる必要はありません。
残念ながら、このタイプのループは Ruby には存在しないようです。誰かこれを行うより良い方法を提案できますか?
解決
注意:
開始< code> < condition>
がRubyの作者Matzによって拒否されている間に終了します。代わりに、彼は Kernel#loop
の使用を提案します。例えば、
loop do
# some code here
break if <condition>
end
メール交換 2005年11月23日、マッツは次のように述べています。
|> Don't use it please. I'm regretting this feature, and I'd like to
|> remove it in the future if it's possible.
|
|I'm surprised. What do you regret about it?
Because it's hard for users to tell
begin <code> end while <cond>
works differently from
<code> while <cond>
RosettaCode wiki にも同様のストーリーがあります:
2005年11月、Rubyの作成者である松本幸宏は、このループ機能を後悔し、Kernel#loopの使用を提案しました。
他のヒント
Rubyコアライブラリの
Tempfile#initialize
のソースを読み取り中に、次のスニペットを見つけました。begin tmpname = File.join(tmpdir, make_tmpname(basename, n)) lock = tmpname + '.lock' n += 1 end while @@cleanlist.include?(tmpname) or File.exist?(lock) or File.exist?(tmpname)
一見、begin ... endの内容の前にwhile修飾子が評価されると仮定しましたが、そうではありません。観察:
>> begin ?> puts "do {} while ()" >> end while false do {} while () => nil
期待どおり、ループは修飾子がtrueの間実行を続けます。
>> n = 3 => 3 >> begin ?> puts n >> n -= 1 >> end while n > 0 3 2 1 => nil
このイディオムを二度と見たくないのですが、begin ... endは非常に強力です。以下は、パラメータなしで1行メソッドをメモする一般的なイディオムです。
def expensive @expensive ||= 2 + 2 end
これはいですが、もっと複雑なものを簡単にメモする方法です:
def expensive @expensive ||= begin n = 99 buf = "" begin buf << "#{n} bottles of beer on the wall\n" # ... n -= 1 end while n > 0 buf << "no more bottles of beer" end end
元は Jeremy Voorhis によって作成されました。元のサイトから削除されたと思われるため、コンテンツはここにコピーされました。コピーはウェブアーカイブおよび Rubyバズフォーラム。 -トカゲの請求書
これに似ています:
people = []
begin
info = gets.chomp
people += [Person.new(info)] if not info.empty?
end while not info.empty?
リファレンス: RubyのHidden do {} while()Loop
これはどうですか?
people = []
until (info = gets.chomp).empty?
people += [Person.new(info)]
end
これは、hubbardrの私のブログへのリンクからの全文記事です。
Rubyコアライブラリの Tempfile#initialize
のソースを読み取り中に、次のスニペットを見つけました。
begin
tmpname = File.join(tmpdir, make_tmpname(basename, n))
lock = tmpname + '.lock'
n += 1
end while @@cleanlist.include?(tmpname) or
File.exist?(lock) or File.exist?(tmpname)
一見、 while
修飾子は begin ... end
の内容の前に評価されると仮定しましたが、そうではありません。観察:
>> begin
?> puts "do {} while ()"
>> end while false
do {} while ()
=> nil
期待どおり、ループは修飾子がtrueの間実行を続けます。
>> n = 3
=> 3
>> begin
?> puts n
>> n -= 1
>> end while n > 0
3
2
1
=> nil
このイディオムを二度と見たくないのですが、 begin ... end
は非常に強力です。以下は、パラメータなしで1行メソッドをメモする一般的なイディオムです。
def expensive
@expensive ||= 2 + 2
end
これはいですが、もっと複雑なものを簡単にメモする方法です:
def expensive
@expensive ||=
begin
n = 99
buf = ""
begin
buf << "#{n} bottles of beer on the wall\n"
# ...
n -= 1
end while n > 0
buf << "no more bottles of beer"
end
end
これで正しく動作するようになりました。
begin
# statment
end until <condition>
ただし、将来的には削除される可能性があります。 begin
という発言は直観に反しています。見る: http://blade.nagakiut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/6745
Matz は次のようにすることを推奨しました。
loop do
# ...
break if <condition>
end
私が収集したものから、マッツはその構造が好きではありません
begin
<multiple_lines_of_code>
end while <cond>
理由は、セマンティクスが次と異なるためです
<single_line_of_code> while <cond>
最初のコンストラクトは、条件をチェックする前に最初にコードを実行するため、 また、2番目の構造は、コードを実行する前に(もしあれば)最初に条件をテストします。 Matzはifステートメントの1行のコンストラクトに一致するため、2番目のコンストラクトを保持することを好みます。
ifステートメントであっても、2番目の構造は好きではありません。その他の場合はすべて、コンピューター コードを左から右(たとえば、||および&amp;&amp;)で上から下に実行します。人間は左から右にコードを読む 上から下へ。
代わりに次の構成体をお勧めします:
if <cond> then <one_line_code> # matches case-when-then statement
while <cond> then <one_line_code>
<one_line_code> while <cond>
begin <multiple_line_code> end while <cond> # or something similar but left-to-right
これらの提案が他の言語で解析されるかどうかはわかりません。しかし、いずれにせよ 左から右への実行と言語の一貫性を保つことを好みます。
a = 1
while true
puts a
a += 1
break if a > 10
end
もう1つあります:
people = []
1.times do
info = gets.chomp
unless info.empty?
people += [Person.new(info)]
redo
end
end
ppl = []
while (input=gets.chomp)
if !input.empty?
ppl << input
else
p ppl; puts "Goodbye"; break
end
end