Rubyの文字列リテラルではダブルクオートを基本としたい
Ruby では大きく分けて3種類の文字列リテラル*1がありますが、どのように使い分けるのが適切か、自分なりの結論に達したのでまとめておきます。
結論
まず先に結論から書いておくと*2、
- 基本はダブルクオートを使用する
- 意図的に式展開を抑制したい場合にのみシングルクオートを使用する
が最も適切な使い分けだと思います。
これは、Ruby Style Guide の 文字列リテラルスタイルの Option B と同じです。
文字列中に"を含んでいたり、エスケープ文字を抑えたいときでない限り、 ダブルクォーテーションが好まれます。
つまり、文字列リテラルは Ruby Style Guide の Option Bを採用するのが最も適切 だと考えています。
以下、 Option A と Option B で揺れ動き、最後に Option B に到達した理由を説明していきます。
文字列リテラル一覧
3種類の文字列リテラルには以下のとおりです。
- シングルクオート
- ダブルクオート
- パーセント記法
Ruby Style Guide でも Consistent String Literals とあるように、最も大切なことは首尾一貫して同じ記法を使うことだと思います。 正直、最低でもリポジトリ単位でその一貫性が守られていたら何を使っても良いと思っています。
そのため、今から述べる説明は「これから文字列リテラルを選ぶ時、どれを採用すると良いのか」という自分なりの考えとなります。
それでは順を追ってどれが良いかを考えていきます。
パーセント記法の除外
Ruby Style Guide に以下のように記載されている通り、%q
などは基本の文字列リテラルにすべきではないと思います。
文字列に'と"双方が含まれない限り、 %qの使用は避けましょう。 たくさんの文字列をエスケープしなくてもよいときは、 通常の文字列リテラルのほうがより読みやすく、 推奨されるべきです。
Ruby の最も有名な静的コード解析ツールである RuboCop のベースルールとなっている Ruby Style Guide*3 には基本的に従うのが吉だと思います。
通読したことがありますが、とても良いと感じました。もちろん、プロジェクトごとに調整は必要だとは思います。
シングル vs ダブル
さて、残るはシングルクオートかダブルクオートかです。
Ruby Style Guide ではなんと、どちらも推奨されています。つまり、自分の判断やプロジェクトの方針で選べば良い、ということですね。
それぞれの客観的なメリットとデメリットをまずは挙げてみたいと思います。
シングルクオートのメリット
- ダブルクオート文字列の時は「この文字列中には式展開がある」ということが一目でわかる
シングルクオートのデメリット
- 文字列中の式展開の有無が変わった際にシングルクオートとダブルクオートを入れ替える必要がある
ダブルクオートのメリット
- シングルクオート文字列の時は「この文字列では式展開を意図的に抑制している」ということが一目でわかる
ダブルクオートのデメリット
- 文字列中の式展開の抑制の必要の有り無しが変わった際に、シングルクオートとダブルクオートを入れ替える必要がある
これだけ並べると、どっちもどっちですね。
Ruby Style Guide で両者を選択制にしている理由が容易に見て取れます。
それでは、ここからは自分なりの考えを書いていきたいと思います。
シングルクオートのメリットへの意見
自分の経験上、このシングルクオートかダブルクオートかの違いを見て、式展開の有無を判断したことはほぼありません。
その理由として、大体の場合に置いて式展開があるとシンタックスハイライトが効いてひと目で分かるからです。
もしシンタックスハイライトが効かない状況であれば、その式に展開が含まれてるかどうかがひと目でわかるのは間違いないです。
ただ、実際に文字列を眺める際に「この文字列は展開があるのかな?無いのかな?」と見ることは個人的にはあまりないかなと思っています。なぜならシンタックスハイライトが効かなくても、よっぽど長くてわかりにくい文字列じゃない限り、そこに式展開やエスケープシーケンスが含まれているかどうかは、すぐにわかるからです。#{}
とか\
とか結構目立ちます。
そのため、シングルクオートかダブルクオートかを役立てる際は、「エスケープシーケンスなどが文字列中に含まれてる場合にそれが展開されるのか展開されないのかの判断」に使うことになります。
これはつまり、「シングルクオートかダブルクオートかによって、式展開が抑制されているかどうかを判断する際に役立つ」ということになりますね。
おや、これはダブルクオートを基本とするの時のメリットと同じですね……?
ダブルクオートを基本とする際との違いは、シングルクオートで囲まれているからと言って、そこで式展開の抑制が行われているかどうかはその囲いの種類からだけでは判断できないという事が挙げられます。完全に劣化してます。
すなわち、式展開の抑制有無に役立てるのであれば、素直にダブルクオートを基本として使うべきという結論になりますね。
この時点で個人的にはシングルクオートのメリットは消失しました。
シングルクオートのデメリットへの意見
文字列中の式展開の有無って、コーディング中に変わることってそこそこあると思います。 「ココは共通項だから抜き出しとくか」とか、「やっぱりコレは違うな」とか、あると思います。
その際にいちいち囲い文字を変えるのは正直面倒ですね。デメリットは立派に生き残りました。
ダブルクオートのメリットへの意見
シングルクオートのメリットへの意見と同じく、シンタックスハイライトが効く状況下ではこの囲い文字で展開有無を判断することはほぼ無いと思います。
もしシンタックスハイライトが効かない場合、式展開が抑制されているかどうかを判断するのにはたしかに役立ちます。
シングルクオートを見た時は「お、この文字列ではあえて何かサプレスしてんだな」とわかって、スッキリシンプル素敵です。
ダブルクオートのデメリットへの意見
文字列中の式展開の有無に比べると、文字列中の式展開の抑制の有無がコロコロ切り替わる場面は少ないと感じます。 デメリットはデメリットですが、シングルクオートのデメリットより煩わしいと感じることは少なそうです。
決着
シングルクオートのメリットは消え去り、デメリットが生き残りました。 そしてダブルクオートのメリットはそのシンプルさが際立ち、デメリットはシングルクオートとの比較で勝利しました。
これはもうダブルクオートを基本にするしか無いですね!
ダブルクオートの主観的メリット
決着をつけた上で、更に主観的メリットを述べておきます。
ダブルクオートを基本として使った場合、
- 基本的に常にダブルクオートを使う
- 式展開を抑制する特殊な状況でのみシングルクオートを使う
という、特殊な状況下でのみ異なるリテラルを使うという一貫性が際立ちます。
シングルクオートの場合も一貫性はあるのですが、
- 基本的に常にシングルクオートを使う
- 式展開が必要な特殊な状況でのみダブルクオートを使う
となりますね。式展開が必要な状況って特殊でしょうか?私はそうは思いません。普通の状況です。 それに比べ、わざわざサプレスするというのは十分に特殊だと感じれます。
ダブルクオートの大勝利!
別言語の例
ダメ押しで自分がコレまでに見たことのある言語を用いてダブルクオート基本論を更にプッシュしてみたいと思います。
C
みんな大好き C 言語の文字列リテラルはダブルクオートです。 シングルクオートは文字リテラルのことですね。
C 言語で Pascal 風言語コンパイラを作った激しい戦いの記憶が蘇ってきた。
C Sharp
みんな大好き C# での文字列リテラルもダブルクオートです。 ココであえて C# を持ってきた理由は、C# に「特殊文字をエスケープしたいときに使える記法がある」からです。
//Initialize with a regular string literal. string oldPath = "c:\\Program Files\\Microsoft Visual Studio 8.0"; // Initialize with a verbatim string literal. string newPath = @"c:\Program Files\Microsoft Visual Studio 9.0";
Ruby で文字列リテラルの基本をダブルクオートにするときと同じ思考プロセスになりますね。 もしかしたら、C# のこの記法があったからそういう思考プロセスになっている可能性もありますが、その他のツールでも、基本的に「必要なときにエスケープする」という利用方法を提供しているものが多い気がします。 プログラミング言語の文字列リテラルと事情が違うのは当然ですが、Bash とか Vim とかでも基本必要なときにエスケープする必要がありますよね。
Ruby でダブルクオートを基本に選べば、コレに乗っかることができるのが良いなと思います。
.NET を使った官公庁との熾烈な戦いの記憶が蘇ってきた。 でも、お台場での .NET 研修は最高だった。
Crystal
Ruby のそっくりさんとして有名な Crystal ですが、なんと文字列リテラルはダブルクオートのみです。 シングルクオートは C 言語と同じく文字リテラルを表します。
実は使ったこと無いので蘇る記憶はありませんでした。
全く関係の無い過去回想が入ってしまいましたが、ダブルクオートが文字列というのが自分にとって自然である理由と、必要な時にエスケープするというプロセスがしっくりくる理由が伝わったかと思います。
おわりに
長々となりましたが、実際これだけのことを考えた上で「俺の Ruby コーディング規約では絶対ダブルクオートだ!」という結論に達しました。
賛同してくださる方は、これからは Ruby Style Guide の Consistent String Literals では Option B を選びましょう!
。:゜☆ヽ(’∀’)/☆゜:。。