
こんにちは、hachi8833です。
「Rubyスタイルガイドを読む」シリーズの文法編その4は、while
やuntil
などのループについてです。
文法(3)
複数行のwhile
やuntil
では条件の後にdo
を置かない
Do not use
while/until condition do
for multi-linewhile/until
.
# 不可
while x > 5 do
#(本文省略)
end
until x > 5 do
#(本文省略)
end
# 良好
while x > 5
#(本文省略)
end
until x > 5
#(本文省略)
end
whileやuntilの文法では、以下のようにdo
はオプションになっています。このスタイルではdo
を置かない方に揃えています。
while 式 [do]
...
end
until 式 [do]
...
end
while
やuntil
の本文が単文の場合は後置にするのが望ましい
Favor modifier
while/until
usage when you have a single-line body.
# 不可
while some_condition
do_something
end
# 良好
do_something while some_condition
仕様にもあるように、while
やuntil
は、後置のif
やuntil
と同様に修飾子として使えるので、うまく使うとコードを簡潔に書くことができます。
# while修飾子
sleep(60) while io_not_ready?
# until修飾子
print(f.gets) until f.eof?
追伸:
while
やuntil
は条件や結果にかかわらずnil
だけを返すのかと思っていたのですが、リファレンス・マニュアルによると式の戻り値を返すこともできるそうです。
- while は nil を返します。また、引数を伴った break により while 式の戻り値をその値にすることもできます。
- while 修飾した式は nil を返します。 また、引数を伴った break により while 修飾した式の戻り値をその値にすることもできます。
- until は nil を返します。また、引数を伴った break により until 式の戻り値をその値にすることもできます。
- until 修飾した式は nil を返します。 また、引数を伴った break により until 修飾した式の戻り値をその値にすることもできます。
Ruby 2.4.0リファレンスマニュアルより
否定条件をwhile
で表すよりも、条件を肯定にしてuntil
にする方が望ましい
Favor
until
overwhile
for negative conditions.
# 不可
do_something while !some_condition
# 良好
do_something until some_condition
プログラミング言語の種類を問わず、否定条件を肯定条件に置き換える方が一般に読みやすくなります。
無限ループはKernel#loop
で書くこと
Use
Kernel#loop
instead ofwhile/until
when you need an infinite loop.
# 不可
while true
do_something
end
until false
do_something
end
# 良好
loop do
do_something
end
文法上はwhile
やuntil
に条件を設定しないことでも無限ループを形成できますが、Kernel#loop
で統一することでwhile
やuntil
の役割をはっきりさせるという意図と理解しました。
begin/end/until
やbegin/end/while
ではなく、Kernel#loop
とbreak
を使う
Use
Kernel#loop
withbreak
rather thanbegin/end/until
orbegin/end/while
for post-loop tests.
# 不可
begin
puts val
val += 1
end while val < 0
# 良好
loop do
puts val
val += 1
break unless val < 0
end
他の言語でいう「do〜while」的な書き方をする場合はKernel#loop
とbreak
に統一します。
暗黙のハッシュを引数として渡す場合、外側の波かっこ{ }
は省略する
Omit the outer braces around an implicit options hash.
# 不可
user.set({ name: 'John', age: 45, permissions: { read: true } })
# 良好
user.set(name: 'John', age: 45, permissions: { read: true })
1つのハッシュのみを引数として渡すときに波かっこを省略できますが、それをスタイルとして指定しています。これは読みやすさのためでしょうね。
なお、この例では以下のようにさらに丸かっこ( )
を省略しても動作しましたが、丸かっこ( )
を省略せよという指示はここにはありません。丸かっこの省略については次の項目をご覧ください。
内部DSLの一部であるメソッドでは、引数の波かっこ{ }
と丸かっこ( )
を両方省略する
Omit both the outer braces and parentheses for methods that are part of an internal DSL.
class Person < ActiveRecord::Base
# 不可
validates(:name, { presence: true, length: { within: 1..10 } })
# 良好
validates :name, presence: true, length: { within: 1..10 }
end
内部DSLはRubyの文法に沿ってはいますが独自に拡張されているため、DSLであることをわかりやすくするためであると理解しました。
今回はここまでとします。次回の文法編はブロック関連です。ご期待ください。