1. ホーム
  2. スクリプト・コラム
  3. ルビートピックス

Rubyプログラミングにおけるアサインメント関連操作

2022-02-12 15:05:47

古いバージョンのRubyでは、代入文の返り値は、プロパティを設定したメソッドの返り値でした。Ruby 1.8では、代入文の値は常に引数の値で、メソッドの戻り値は破棄されます。

class Test
  def val=(val)
    @val = val
    return 99
  end    
end
 
t = Test.new
a = t.val=2
a ->2


 古いバージョンでは、aは代入文によって99に設定されていましたが、Ruby 1.8では2という値を持っています。

Rubyの代入は実際には並列に実行されるので、代入文の右辺の値は代入文自体の影響を受けません。左側の変数やプロパティが代入される前に、右側の値が現れる順番に計算されます。次の人間が設計した例では、この点を説明しています。2行目は、式 x ,x+=1, x+=1 の値をそれぞれ変数 a, b, c に代入することについて述べています。

x = 0 -> 0
a,b,c =x,(x+=1),(x+=1) ->[0,1,2]


代入文が複数の左値を持つ場合、代入式は右値の配列を返します。代入文が右の値より左の値の方が多い場合、余分な左の値は無視されます。もし、左の値より右の値の方が多い場合は、余分な右の値は無視されます。代入文の左値が1つだけで、右値が複数ある場合、右値は配列に変換された後、左値に代入される。

 実は、書き込み可能な属性には、隠れた罠があるのです。通常、あるクラスのメソッドは、同じクラスやその親クラスの他のメソッドを関数として(つまり、暗黙のselfを受け手として)呼び出すことができます。しかし、これはプロパティの割り当て関数には適用されません。Ruby は代入文を見て、左側の名前はローカル変数であり、プロパティに値を代入するメソッド呼び出しではないと判断します。

class BrokenAmplifier
 attr_accessor :left_channel, :right_channel
 def volume=(vol)
   left_channel = self.right_channel = vol     
 end  
end
 
ba = BrokenAmplifier.new
ba.left_channel = ba.right_channel = 99
ba.volume = 5
ba.left_channel ->99
ba.right_channel ->5


  上の代入文では、left_channel の前に "self." を付けるのを忘れたため、Ruby はオブジェクトのプロパティを全く更新しないので、volume= メソッドのローカル変数に新しい値が格納されます。これは追跡困難な不具合になりかねません