2016-06-12 11 views
0

ここでは、遅延評価の概念を示す簡単なプログラムを紹介します。ルビーの遅延評価で何が問題になったのですか

class A 
    def x 
    y += 1 
    end 

    def y 
    @y ||= 0 
    end 
end 

A.new.x 

しかし、私は

NoMethodError: undefined method `+' for nil:NilClass

このプログラムを実行するときにこのような結果を得た私は何か間違ったことをやっていますか?

@yが配列の場合、問題なく動作します。

class A 
    def x 
    y << rand(10) 
    end 

    def y 
    @y ||= [] 
    end 
end 

a = A.new 
a.x 

UPDATE

最後に、私は問題を理解しています。 Rubyは値渡しです。最初の例でメソッドyを呼び出すと、Rubyはinstance_variableを気にせず、@yの値だけをコピーして返します。

第2の例では、Rubyは依然として変数@yの値をコピーして返します。しかし、この場合、@yは実際の配列のポインタであり、このポインタのコピーは同じ配列を指しています。

しかし、なぜエラーがundefined method + for nilであるか、私はyがyの値と等しいことを期待しています。なぜこの場合yがnilになるのですか?

+2

_ _「Rubyは値渡しである」 - あなたは任意の引数を渡すことはありません。 – Stefan

+1

質問であなたが報告したエラーが発生したときは、それが発生した行を指定する必要があります。より一般的には、例外メッセージには、しばしばエラーを特定する貴重な情報が含まれています。それらに細心の注意を払う。 –

答えて

5

y += 1が本当に何を理解することが重要です。あなたはちょうどあなたがローカル変数yy + 1を割り当てるルビーを告げた意味

y = y + 1 

y += 1は同等です。 Rubyは呼び出しメソッドよりもローカル変数からの読み込みを優先するので、ローカル変数の現在の値yを使用し、1を追加しようとします。しかし、現時点でローカル変数yはまだnilなので、この操作ではundefined method '+' for nil:NilClassの例外が発生します。

y += 1は、yというメソッドを呼び出し、1を追加し、結果を@yに戻すことを期待しています。あなたが持っている、これはあなたのコードビットを変更するために達成するために:

self.yあなたがメソッドyを読んで、ローカル変数を作成しないことを保証します。さらにy =を呼び出すには、セッターメソッドattr_writerが必要です。

2番目の例は、どのように機能しますか? <<はローカル変数を作成するショートカットではないため、yから配列を受け取ります。 <<は、y =のようなセッターメソッドを呼び出す必要なく、その配列に値をシフトします。この文脈で

興味深い読み取り:What Ruby’s ||= (Double Pipe/Or Equals) Really Does