2008-02-16 凪いだ青空 [長年日記]
_ Nullの話 〜 NULLとnullとnil 〜
必要があってプログラムの基本を見つめ直している今日この頃です。(^^ゞ
#今日の話も「なんだそんな基本的なことか!」な内容かもしれません。。。
英単語のNULLは「存在しない」とか「無効な」とか「ゼロと等しい」って意味なんですね。
C++だとNULL, Javaだとnull, Rubyだとnilです。
C++でNULLポインターにアクセスすると落ちる(不定?)。
Javaでnullポインターにアクセスすると例外(NullPointerException)発生。
Rubyでnilにアクセスすると
「NoMethodError: undefined method `length' for nil:NilClass」。
ぉぉ、RubyだとnilもNilClassのオブジェクトなのですね。
言語の進化の系譜の一部を覗き見れました。
でもJavaでコードを書いててNullPointerExceptionに遭遇する機会ってどれくらいあるんだろう?
無理矢理書けばできるけど、
shallow copyでスコープを外れてもGarbageCollectionされないし。。。
#参照カウンタが上がるからだよね。
■例文:Javaのshallow copy
int[] out = {1,2,3};
{
int[] in = {4, 5, 6};
out = in;
}
System.gc();
System.out.println(out[0]);
→4
■■Nullの例文
■C++
#include <string>
std::string* str = NULL;
str->length();
→落ちる(不定?)
■Java
String str = null;
str.length();
→java.lang.NullPointerException
■Ruby
str = nil
str.length()
→NoMethodError: undefined method `length' for nil:NilClass
C++の例は、他のと同じ意味で書くとしたら<br><br>std::string* str = NULL;<br>str->length();<br><br>ではないでしょうか?
>あまのりょーさん<br>ですね。修正しました。<br>C++が一番慣れてるのになぁ。(^^;)<br>ご指摘ありがとうございます。m(_ _)m
あ、ごめん、一つ書き忘れてました。<br><br>#include が(ブラウザの表示上)消えてるよ。たぶん、string ヘッダーが書いてあって、(文字実体参照で書いてないから)HTMLタグだと解釈されてるのだと思うけど。
>あまのりょーさん <br>ぅぉ、ホントだ。<br>引用文にした方が見やすそうですが、<br>めんどっちいので全角<>で代用しちゃいました。<br>重ね重ねご指摘ありがとうございます。m(_ _)m
Rubyの例が、Javaのソースになっちょるよw<br><br>Javaでヌルポになることは結構あります。<br>C++で落ちることがあるのと同じぐらいの頻度で。<br><br>「ここで本当はデータが入って来てるはずなのに<br>なぜかデータが取れてこなくてnullになっちゃってるなー」とか。<br><br>Rubyも同様ですね。<br><br>Railsとかで、ビューのレイヤーでnilアクセスで落ちると<br>ムカつくので、こんなラッパを書いて握りつぶしちゃってますw<br>(臭いものにはフタ方式。あまり行儀の良い方法ではない)<br><br><br>--- begin application_helper.rb<br># ブロックの途中で起きたNoMethodErrorが起きたときは<br># 握りつぶして空文字列を返すヘルパ<br>def ga! #ガッ<br> begin<br> yield<br> rescue NoMethodError<br> ""<br> end<br>end<br>--- end application_helper.rb<br><br>--- begin foo.html.erb<br><br><%=h ga! { obj.method_1.method_2.method_n } %><br># objからmethod_nまでのメソッドチェーンのどこかで<br># 予期せぬ nil が発生してもアプリが落ちないようにする<br><br>--- end foo.html.erb<br><br>$ irb<br>>> def ga!<br>>> begin<br>?> yield<br>>> rescue NoMethodError<br>>> ""<br>>> end<br>>> end<br>=> nil<br>>> a = nil<br>=> nil<br>>> ga!{ a.hoge }<br>=> "" # nil にメソッド発行したときは空文字列が表示される<br> # (たった一個のヌルポにためだけにエラー画面になって全ての情報が見られなくなるようなことは避けたい)<br>>> def a.hoge # hoge をちゃんと定義してあげると、、、<br>>> "foobar"<br>>> end<br>=> nil<br>>> ga!{ a.hoge }<br>=> "foobar" # hoge の実行結果が返る
>tmaedaさん<br>Javaでヌルポは結構あるのかー。意外でした。<br>Rubyの例も理にかなってますね。<br><たった一個のヌルポにためだけにエラー画面になって<br> 全ての情報が見られなくなるようなことは避けたい<br>現場の情報ありがとうございました。<br>大変勉強になります。<br>やはり読者の方あってのいがいが日記だなと。(笑)<br><br>あと、Rubyのソースはirbで実行したらできるので<br>問題ないと思うのですがどうでしょう。<br>Ruby風に書くと str.length かもですが。<br>> String str = nil<br>> str.length()
たしか C++0x(次期C++標準)では NULL は nullptr という予約語になるはずです。C での (void*)0 とか C++ での 0 じゃいろいろ問題がありましたからね。
> あと、Rubyのソースはirbで実行したらできるので <br>> 問題ないと思うのですがどうでしょう。<br><br>あぁ、そっか。すんません。<br>頭にいきなり「String」なんてあったので、<br>脊髄反射で「これはRubyじゃない」と判断してしまいましたが、<br>文法的には正しいようですね。<br><br>Rubyでは基本的に型の指定などは書きませんので、<br>頭にStringとかは書きません。<br><br>じゃ、いがいがが書いたStringは一体何をしているかというと、<br>これは型の指定として働いているわけではなく、<br>KernelクラスのStringメソッドを起動したことになり、<br>引数の a (中身はnil)にto_s を発行した結果を返しているだけになります。<br>詳しくはマニュアル参照。<br> http://www.ruby-lang.org/ja/man/html/_C1C8A4DFB9FEA4DFB4D8BFF4.html<br><br>なので、この文脈での正しいコードは<br>str = nil<br>str.length (カッコをつけるかつけないかはどっちでもいい)<br>となります。
みなさんツッコミありがとうございます!<br>大変勉強になっています!!<br><br>>bear.miniさん<br>おお、予約語になるんですね。<nullptr<br> (void*)0 とか¥0とか違いを把握できてないので、予約語化賛成!<br> ↑あまり本質じゃないとこで覚えること多すぎ。。。<br> <br> >tmaedaさん<br>しまった、Rubyは宣言しないんでしたね。。。<br>全然違う意味のコードを書いてしまってたのか。<br>メソッドの()が省略できるのは便利ですが、<br>気づかずへんてこなコードになることもあるのだなぁ。<br>注意しよう。<br>str = String.new<br>str = nil<br>str.length()<br>って書くのがC++/Javaと似た意味になりそうですけど、<br>2行目で「nilオブジェクトを参照しろ!」って言っちゃうから1行目無意味ですね。。。
NULL はヌルと呼ぶ人が多く、NUL はナルと呼ぶ人が多い。<br>不思議。自分もそうだけど。
>ちゃーりー さん<br>あー、確かに!<ぬる、なる<br>呼び分けておいた方が便利だからですかね。<br>NULの方があんま見ないですけど、<br>ASCII文字とCの文字列最後(¥0かな)はNULみたいですね。<br>http://en.wikipedia.org/wiki/NUL