更新日:
【Ruby】 unlessの使い方を正しく学んで可読性を下げないようにしよう
unlessとは、条件式の判定によって処理が分岐される制御構造のひとつです。条件式を評価した結果が偽の場合にthen以下に記述する(式を評価)処理が実行されます。
unlessは、unlessのあとに記述する条件式が偽の場合にthen~endまでの処理を実行します。
1
2
3
unless 条件式 [then]
# 条件式が偽の時に実行する処理
end
例えば、次のコードではbreakfastに'パン'
が代入されているので、条件式のbreakfast == 'ご飯'
は偽になり、ご飯ではありません。
が出力されます。
1
2
3
4
5
6
breakfast = 'パン'
unless breakfast == 'ご飯' then
puts 'ご飯ではありません。'
end
#=>ご飯ではありません。
この記事では、unlessの使い方や処理の流れ、可読性における注意点など学ぶことができます。1つ1つ整理しながら理解を深めていきましょう。
unlessの使い方
この章では、unlessの書き方や処理の流れ、返り値など基本的な部分について解説します。
基本構文
unlessは、次のようにunless~end
までが範囲になります。
1
2
3
unless 条件式 [then]
# 条件式が偽の時に実行する処理
end
unless
- 条件式を記述します。then以下
- 条件式が偽の場合に実行する処理を記述します。
unless 条件式 then
とは「条件式
を評価した結果が偽の場合にthen
以下の式を評価する」という意味になります。
また、次のようにunlessはelse
を使うことができます。
1
2
3
4
5
unless 条件式 [then]
# 条件式が偽の時に実行する処理
else
# 条件式が真の時に実行する処理
end
「可読性における注意点」の章で詳しく解説しますが、可読性の問題やifで事足りることからunlessでelseが使われることは多くありません。
※thenは省略することができます。(この章以降はthenを省略します。)
処理の流れ
記事の冒頭では、unlessについて下記のように記述しました。
unlessの後に記述する条件式を評価した結果が偽の場合は、then以下に記述する式を評価します。
この処理の流れをサンプルコードで表すと、次のような順番になります。
breakfast == 'ご飯'
の条件式が評価される。(偽という評価結果になる)- then以下の式が評価されて、
ご飯ではありません。
が出力される。
上記の「条件式が評価される。」とありますが、次の動画のように式(breakfast == 'ご飯'
)を実行して値を得ることを「評価」といい、値(false
)が評価の結果になります。※Rubyではfalse
またはnil
が偽です。
つまり、unlessは条件式の評価結果がfalseならば、then以下の式を評価します。
返り値
unlessの返り値は、条件が成立しなければthen以下の最後に評価した式の結果を返し、条件が成立すればnilを返します。
例えば、次のように条件式の評価結果が偽だと式の評価結果("条件が不成立"
)を返し、条件式の評価結果が真だとnil
を返します。
1
2
3
4
irb(main):001:0> unless 1 == 10
irb(main):002:1> "条件が不成立" # 条件式が偽なので、この式が評価される
irb(main):002:1> end
=> "条件が不成立"
1
2
3
4
irb(main):001:0> unless 1 == 1
irb(main):002:1> "条件が成立" # 条件式が真なので、この式は評価されない
irb(main):002:1> end
=> nil
先ほどの補足説明で少し触れましたがunlessは値を返す式なので、次のように変数に代入して使用することもできます。
後置unless(unless修飾子)
unlessは後置unless(unless修飾子)を使用すると、1行で記述することができます。
1
2
式 unless 式
# [条件式が偽の時に実行する処理] unless [条件式]
後置unlessでは、右辺の条件が成立しない(偽になる)場合に左辺の式を評価し、その評価結果を返します。
例えば、これまでの解説に使用していたサンプルコードを後置unlessにすると、次のように記述することが出来ます。
1
2
3
4
5
6
7
8
9
breakfast = 'パン'
# 後置unlessを使用しない場合
unless breakfast == 'ご飯'
puts 'ご飯ではありません。'
end
# 後置unlessを使用した場合
puts 'ご飯ではありません。' unless breakfast == 'ご飯'
このように後置unlessは、1行に記述するコードが短い場合に使用することで、簡潔に記述することができます。
しかし、1行に記述するコードが長い場合に後置unlessを使用すると可読性が下がります。
例えば、次のコードはどうでしょうか?
1
puts '今日の朝食はご飯ではありません。しかし、明日の朝食はご飯にしようか検討中です。他にも候補はあります。' unless breakfast == 'ご飯'
コードを右端まで読んではじめてbreakfast == 'ご飯'
ではないときにputs ~
の処理を実行することがわかりますね。1行に記述するコードが長くなる場合は後置unlessを使用しない方が読みやすくなります。
1
2
3
unless breakfast == 'ご飯'
puts '今日の朝食はご飯ではありません。しかし、明日の朝食はご飯にしようか検討中です。他にも候補はあります。'
end
コードの記述量が減るので後置unlessに置き換えた方が良さそうと思われがちですが、下手すると可読性が下がり読みづらいコードになってしまうので使用する際は注意が必要です。
可読性における注意点
unlessはいくつかの状況に使うと、混乱するようなかえって読みにくいコードになります。
この章では特に可読性に関わる以下の注意点について解説します。
- unlessとelseの併用を避けよう
- unlessとnot演算子の併用を避けよう
- 対義語メソッドで肯定にできるか検討しよう
- unlessと||の併用を避けよう
unlessとelseの併用を避けよう
次のようにunless~else
はif~else
に置き換えることができるので、頻繁に使われるものではありません。
1
2
3
4
5
unless true
# 条件式が偽の時に実行する
else
# 条件式が真の時に実行する
end
1
2
3
4
5
if true
# 条件式が真の時に実行する
else
# 条件式が偽の時に実行する
end
またunless~else
はelseの箇所で二重否定(trueでなくない)になり、読みづらいコードが出来上がってしまうので避けるようにしましょう。
以下はunless~else
をif~else
に置き換えたコードの例です。
1
2
3
4
5
6
7
8
9
10
11
12
13
unless number.even?
"偶数ではありません"
else
"偶数です。"
end
# 上記のunlessは以下のifに置き換えられる
if !number.even?
"偶数ではありません"
else
"偶数です。"
end
ifの条件式にnot演算子!
を指定することで、同じ意味で記述することができています。
unlessとnot演算子の併用を避けよう
先ほどのifの条件式にはnot演算子!
を使っていましたが、unlessの条件式にnot演算子を使うと二重否定になってしまうので使用を避けるようにしてください。
次のunless !true
は、「trueでなくなければ~」という二重否定になります。
1
2
3
unless !true
# 条件式が真の時に実行する
end
上記はtrueの場合に実行されたら良いので、次のようにifに置き換えることができます。
1
2
3
if true
# 条件式が真の時に実行する
end
例えば、unless!number.even?
は二重否定で「numberが偶数でなくないならば~」と理解しづらいですが、結局「numberが偶数ならば~」を意味しているので、次のように置き換えることができます。
1
2
3
4
5
6
7
8
9
unless !number.even?
puts "偶数です。"
end
# 上記のunlessは以下のifに置き換えられる
if number.even?
"偶数です。"
end
このようにnot演算子をunlessの条件式に使うと、コードが読みづらくなってしまうので注意が必要です。
対義語メソッドで肯定にできるか検討しよう
unlessの条件式でメソッドを使うときは、場合によっては対義語メソッドでifに置き換えることができます。
次のコードはeven?メソッドの対義語であるodd?メソッドを使って置き換えています。
1
2
3
4
5
puts "奇数です。" unless number.even?
# 上記のunlessは以下のifに置き換えられる
puts "奇数です。" if number.odd?
「numberが偶数ではければ」から「numberが奇数ならば」と肯定の形になるので、否定よりも読みやすくなりますね。
また、blank?メソッドを使う場合は、present?メソッドを使うことでifに置き換えることができます。(どちらもActiveSupportが提供するメソッドです。)
1
2
3
4
5
puts "空ではありません。" unless number.blank?
# 上記のunlessは以下のifに置き換えられる
puts "空ではありません。" if number.present?
こちらも「numberが空でなければ」から「numberが存在すれば」と肯定の形になるので、読みやすくなります。