こんにちは! フリーエンジニアの長瀬です。
みなさんはnilをうまく扱う方法をご存じですか?今日はRubyのnilについて解説していきたいと思います。nilはプログラミング独特の概念で初心者の方は特に戸惑いやすい知識です。
そんなnilについて
- nilとは
- NilClassとは
- nilの判定
- if文の条件式でのnilとfalse
という基本的な内容から、
- nilガード
- compactで配列の中のnilを取り除く
といった応用的な内容についても解説していきます。
nilの基本的な知識
nilとは
nilとは一言で言うと「何も存在しない」という意味です。何もないと言われると、「数字の0」や「空集合」や「false」などをイメージされるかもしれませんが、それらはプログラミング界では「存在するもの」として扱われます。
[nilじゃないものの例]
array = [] zero = 0 false_var = false
上記の例では、確かに[]や0、そしてfalseは存在していてnilではないんです。
[nilである例]
nil_var = nil
nilを代入しているのでこちらはもちろんnilです。とにかく、nilと聞いたら、「何もない」というイメージを持つようにしましょう。
NilClassとは
値nilをもつ変数にempty?メソッドを使用すると、
undefined method `empty?' for nil:NilClass (NoMethodError)
などのようなエラーメッセージが表示されます。このエラーメッセージ中にある「NilClass」は、nilが属しているクラスです。nilは「NilClass」クラスのオブジェクトです。
そのため、nilオブジェクトの持つインスタンスメソッドとクラスメソッドは、「NilClass」クラスで定義されたインスタンスメソッドとクラスメソッドのみになります。
そして、「empty?」メソッドは「NilClass」クラスには定義されていないメソッドですので、先ほどの「nil:NilClass (NoMethodError)」というエラーメッセージが表示されるということになります。
しかし、変数の初期値はnilですし、プログラム中で変数の値やメソッドの返値がnilになることはよくあることです。いちいち、変数の値やメソッドの返値がnilになっているかどうかで、「empty?」などの便利なメソッドが使用できずにエラーとなってしまうのは、少々使い勝手が悪いところです。
そこで、Rubyでは、「nilガード」という方法がよくとられます。「nilガード」については、以降の章を参照してください。
nilの判定
nil?
次にnilの判定について見ていきましょう。Rubyでnilかどうかを判断するためにはnil?メソッドを使用します。
nil_var = nil if nil_var.nil? puts "nil_varはnilです。" end
[実行結果]
nil_varはnilです。
このように、nil?メソッドではレシーバーがnilのときtrueを返し、nilではない場合falseを返します。
empty?
nil?とよく似たメソッドに「empty?」があります。empty?は入れ物は存在するが、値がない状態を指します。empty?メソッドはnilに使用するとエラーが出てしまうので注意が必要です。
nil_var = nil empty_var = [] nil_var.empty? empty_var.empty?
[実行結果]
NoMethodError: undefined method `empty?' for nil:NilClass true
このように、[]に対してempty?を使用した場合は空の場合はtrueが返ってきますが、nilに対してはNoMethodErrorという例外が走ります。「NilClassに対してはempty?メソッドは定義されていません」というエラーです。
blank?
blank?はnil?とempty?を合体させたメソッドです。さきほどの例ではnilと空の配列[]にempty?メソッドを使用したところ、nilの場合にはエラーとなりましたが、blank?メソッドを使えば、nilでも空でも判定できます。
blank?はRailsで拡張されているメソッドなので、使用する場合は‘active_support’と ‘active_support/core_ext’をrequireして呼び出してあげる必要があります。
require 'active_support' require 'active_support/core_ext' nil_var = nil empty_var = [] p nil_var.blank? p empty_var.blank?
[実行結果]
true true
このように、「nil」なのか「空」なのか気にする必要がないので、とても便利です。
present?
present?はblank?とは逆で、具体的な値があるもの(nilでなく、空でないもの)に対してtrueを返します。
require 'active_support' require 'active_support/core_ext' nil_var = nil empty_var = [] p nil_var.present? p empty_var.present?
[実行結果]
false false
nilと[]は具体的な値がないので、falseとなりました。
if文の条件式でのnilとfalse
nilは、nil?やblank?でtrueとなりました。present?ではfalseとなりました。では、nilをif文の条件式中にそのまま書くと、if文はどのような値として扱うのでしょうか?答えは、「if文中のnilはfalseとして扱われる」です。
if文中で、falseと同等の値として扱われるのはnilだけです。falseとnil以外の値、たとえば、0、[],””などはtrueとして扱われます。実際のサンプルコードを見てみましょう。
if nil p "nil=true" else p "nil=false" end if 0 p "0=true" else p "0=false" end if [] p "[]=true" else p "[]=false" end if "" p '""=true' else p '""0=false' end
[実行結果]
if_nil_false.rb:23: warning: string literal in condition "nil=false" "0=true" "[]=true" """=true"
実行結果中で、コードの23行目で警告が出ています。これはif文中で空の文字列””を使用しているので問題ないかどうか念のためRubyが警告してくれています。
それ以降の実行結果では、if文中でfalseとして扱われているのはnilだけで、後の0や、[]、””などはtrueとして扱われていることがわかります。
nilの応用的な使い方
nilガード(nil代入・nilチェック)
上のempty?メソッドでエラーが出たように、nilをレシーバとしてメソッドを使うとエラーが出てしまうことはよくあります。nilになってしまう状態を防ぐためにnilガードという書き方がrubyには存在します。nilガードを言葉で説明すると、「もし変数がnilだった場合、値を入れる構文」です。
このように、nilかどうかをチェックし、nilだった場合、nil以外の値を代入するコードのことを、「nilガード」と言います。nilガードを実装するにはorに使われるパイプ演算子||と=を組み合わせます。
[nilガードの例1]
a = nil a ||=3 puts a
[実行結果]
3
[nilガードの例2]
a = 23 a ||=3 puts a
[実行結果]
23
このように、変数aがnilである時だけ変数が代入されています。
反対に、||=を使った代入方法では、レシーバー(今回はa)がnilやfalse以外の場合には代入は行われません。(なので23がそのまま返ってきてます)nilガードのコードをもう少しわかりやすい形にしたコードが、以下のサンプルコードです。
a = nil a = a || 3 puts a
[実行結果]
3
ここに「a = a || 3」とあるように、「a」に「a || 3」を代入しています。「a || 3」は、「もし、aがnilかfalseだったら、値は3となる」という意味ですので、前述の通り、「a || 3」は値「3」となり、最終的に「a」には「3」が代入される、という結果になります。
このnilガードの構文はよく使用されるので覚えておくようにしましょう。
compactで配列の中のnilを取り除く
配列の中にnilが混ざっている場合はcompactメソッドを使うと一気にnilを取り除けるので便利です。
array = [nil,nil,1,nil,2,nil,3,nil,4] p array.compact
[実行結果]
[1,2,3,4]
このようにすっきりとnil以外の値を使ってarrayを出力できます。非常に便利なので覚えておきましょう。
まとめ
いかがでしたでしょうか?この記事では、rubyのnilについて解説しました。
学習のポイントを振り返ってみましょう!
- nilは変数の中が「何もない」状態を示す値(マーク)
- NilClassはnilが属しているクラスで、nilはNilClassのインスタンスメソッドとクラスメソッドを持つが、それ以外は持たない。
- nilの判定には、nil?、empty?、blank?、present?などが使用できる。ただし、empty?だけはnilには使用できない。
- if文の条件式では、nilはfalseとして扱われる。
- 変数にnilが入っていた場合のみ代替値を代入する方法として「nilガード」という定形の方法がある。
- 配列中にたくさんnilが入っている場合、compactメソッドによって、配列中のnilをすべて除去できる。
nilはプログラミング独特の概念のため理解がしにくいところです。しかしnilを理解することはプログラミングをする上で必須になります。とにかくnilは「なにもない」のであって、中身だけない「空」の状態とは違うということが理解できていれば最低限は大丈夫です。
また、blank?やpresent?はRailsで拡張された機能ですが、rubyでも使えるのでぜひ使用してください。もしnilについて忘れてしまったらこの記事を確認してくださいね!