こんにちは、hachi8833です。
「Rubyスタイルガイドを読む」シリーズ文法編、第6回目をお送りします。
文法(6) 演算子など
2-38【統一】分岐の条件部分で=
による代入の結果を値として使う場合は、条件全体をかっこ( )
で囲むこと
Don't use the return value of
=
(an assignment) in conditional expressions unless the assignment is wrapped in parentheses. This is a fairly popular idiom among Rubyists that's sometimes referred to as safe assignment in condition.
# 不可 (+ a warning)
if v = array.grep(/foo/)
do_something(v)
# コード
end
# 良好 (MRIでは警告されるかもしれないが、RuboCopでは警告されない)
if (v = array.grep(/foo/))
do_something(v)
# コード
end
# 良好
v = array.grep(/foo/)
if v
do_something(v)
# コード
end
代入=
の結果を条件式に使うことについて、「==
と間違えたように見えて気持ち悪いから嫌だ」という意見と「いや、=
を条件に書く方が簡潔でいいじゃないか」という意見がよく衝突します。「代入の結果を使う場合は条件全体をかっこ( )
で囲む」というのは、おそらく両者の間を取ったのでしょう。
なお、私もときどきわからなくなっていましたが、代入演算子=
が返す結果は「true/false」ではなく「代入された値」です。
2-39【統一】できるだけ自己代入演算子を使う
Use shorthand self assignment operators whenever applicable.
# 不可
x = x + y
x = x * y
x = x**y
x = x / y
x = x || y
x = x && y
# 良好
x += y
x *= y
x **= y
x /= y
x ||= y
x &&= y
自己代入演算子を使わないスタイルはそれはそれで読みやすいというメリットもあると思いますが、これもどちらが正しいとかではなく、自己代入演算子を使う方に揃えたということですね。
2-40【統一】 「変数が初期化されていない場合のみ初期化する」場合は、||=
を使う
Use
||=
to initialize variables only if they're not already initialized.
# 不可
name = name ? name : 'Bozhidar'
# 不可
name = 'Bozhidar' unless name
# 良好 - nilかfalseの場合のみ'Bozhidar'が代入される
name ||= 'Bozhidar'
三項演算子や後置のif/unlessではなく、最も短く簡潔に書ける||=
に揃えるのは納得です。
2-41【統一】論理値の初期化には||=
を使わないこと
Don't use
||=
to initialize boolean variables. (Consider what would happen if the current value happened to befalse
.)
1つ上のスタイルの例外ということになります。Rubyではnilとfalseの論理値が同じであるため、||=
での初期化には向いていませんね。
# 不可 - enabledの値がfalseであってもtrueになってしまう
enabled ||= true
# 良好
enabled = true if enabled.nil?
2-42【統一】「その変数が存在する場合のみ値を代入する」 処理には&&=
を使う
Use
&&=
to preprocess variables that may or may not exist. Using&&=
will change the value only if it exists, removing the need to check its existence withif
.
# 不可
if something
something = something.downcase
end
# 不可
something = something ? something.downcase : nil
# ok
something = something.downcase if something
# 良好
something = something && something.downcase
# better
something &&= something.downcase
&&=
ならif/unlessや三項演算子が不要になるので、これも納得です。
2-43【統一】===
はなるべく避ける
Avoid explicit use of the case equality operator
===
. As its name implies it is meant to be used implicitly bycase
expressions and outside of them it yields some pretty confusing code.
# 不可
Array === something
(1..100) === 7
/something/ === some_string
# 良好
something.is_a?(Array)
(1..100).include?(7)
some_string.match?(/something/)
#640の変更を反映しました。
この間TechRachoで取り上げたばかりの===
演算子ですが、ここではcase equality operatorと呼んでおり、その名のとおりcase
文で暗黙に使われるのが本来なのでそれ以外の場所で使うべきではないとのことです。
case equalityは大文字小文字を区別するのかと思ってしまいましたが、違いました。
case は一つの式に対する一致判定による分岐を行います。when 節で指定された値と最初の式を評価した結果とを演算子 === を用いて 比較して、一致する場合には when 節の本体を評価します。
Rubyリファレンスマニュアル: caseより
2-44【統一】eql?
は必要ない限り使わない: 極力==
を使う
Do not use
eql?
when using==
will do. The stricter comparison semantics provided byeql?
are rarely needed in practice.
# 不可 - eql? は文字列比較では == と同じ
'ruby'.eql? some_str
# 良好
'ruby' == some_str
1.0.eql? x # これは許容される: eql?はIntegerの1とFloatの1を区別するのに必要
#eql
は上のようにやや厳密な比較を行いますが、「現実にはeql?
はめったに使わない」だそうです。
オブジェクトと other が等しければ真を返します。Hash で二つのキー が等しいかどうかを判定するのに使われます。
このメソッドは各クラスの性質に合わせて再定義すべきです。 多くの場合、 == と同様に同値性の判定をするように再定義されていますが、 適切にキー判定ができるようにより厳しくなっている場合もあります。
デフォルトでは equal? と同じオブジェクト の同一性判定になっています。
このメソッドを再定義した時には Object#hash メソッ ドも再定義しなければなりません。
Rubyリファレンスマニュアル: Object#eql?より
2-45【統一】Perl由来の特殊変数($:
や$;
など)は極力避けること
Avoid using Perl-style special variables (like
$:
,$;
, etc. ). They are quite cryptic and their use in anything but one-liner scripts is discouraged.
Use the human-friendly aliases provided by theEnglish
library.
# 不可
$:.unshift File.dirname(__FILE__)
# 良好
require 'English'
$LOAD_PATH.unshift File.dirname(__FILE__)
個人的にも$
で始まる変数群はとてもわかりにくいうえに、目にイガイガして残念だと思っているので、このスタイルには賛成です。
たとえば$&
なら#last_match
にしたいところです。
/(.)(.)/ =~ "ab"
p Regexp.last_match # => #<MatchData:0x4599e58>
p Regexp.last_match(0) # => "ab"
p Regexp.last_match(1) # => "a"
p Regexp.last_match(2) # => "b"
p Regexp.last_match(3) # => nil
Rubyの特殊変数とよりよい表記の一覧については、次のTechRacho記事をご覧ください。
2-46【統一】メソッド名と開きかっこ(
の間にはスペースを置かない
Do not put a space between a method name and the opening parenthesis.
# 不可
f (3 + 2) + 1
# 良好
f(3 + 2) + 1
スペースに関するスタイルはソースコードレイアウトに置いて欲しいですね(´・ω・`)。
追伸
虎塚さんの記事を読んでいてたまたま気づいたのですが、今回扱ったRubyのコーディングスタイルは『Effective Ruby』にも同じ指摘があるようです。
[tmkm-amazon]4798139823[/tmkm-amazon]
関連記事
- Rubyスタイルガイドを読む: ソースコードレイアウト(1)エンコード、クラス定義、スペース
- Rubyスタイルガイドを読む: ソースコードレイアウト(2)インデント、記号
- Rubyスタイルガイドを読む: 文法(1)メソッド定義、引数、多重代入
- Rubyスタイルガイドを読む: 文法(2)アンダースコア、多重代入、三項演算子、if/unless
- Rubyスタイルガイドを読む: 文法(3)演算子とif/unless
- Rubyスタイルガイドを読む: 文法(4)ループ
- Rubyスタイルガイドを読む: 文法(5)ブロック、proc
- Rubyスタイルガイドを読む: 文法(6)演算子など
- Rubyスタイルガイドを読む: 文法(7)lambda、標準入出力など
- Rubyスタイルガイドを読む: 文法(8)配列や論理値など
- Rubyスタイルガイドを読む: 命名
- Rubyスタイルガイドを読む: コメント、アノテーション、マジックコメント
- Rubyスタイルガイドを読む: クラスとモジュール(1)構造
- Rubyスタイルガイドを読む: クラスとモジュール(2)クラス設計・アクセサ・ダックタイピングなど
- Rubyスタイルガイドを読む: クラスとモジュール(3)クラスメソッド、スコープ、エイリアスなど
- Rubyスタイルガイドを読む: 例外処理
- Rubyスタイルガイドを読む: コレクション(Array、Hash、Setなど)
- Rubyスタイルガイドを読む: 数値、文字列、日時(日付・時刻・時間)
- Rubyスタイルガイドを読む: 正規表現、%リテラル、メタプログラミング(最終回)