web-dev-qa-db-ja.com

インスタンス変数:self vs @

コードは次のとおりです。

class Person
  def initialize(age)
    @age = age
  end

  def age
    @age
  end

  def age_difference_with(other_person)
    (self.age - other_person.age).abs
  end

  protected :age
end

私が知りたいのは、@ageメソッドでself.ageage_difference_withを使用することの違いです。

174
sarunw

@ageと記述すると、インスタンス変数@ageに直接アクセスします。 self.ageを書き込むと、オブジェクトにメッセージageを送信するように指示します。これは通常、インスタンス変数@ageを返しますが、ageメソッドは特定のサブクラスに実装されます。たとえば、実際よりも常に10歳若い年齢を常に報告するMiddleAgedSocialiteクラスがあるとします。または、より現実的には、PersistentPersonクラスは永続ストアからそのデータを遅延的に読み取り、その永続データをすべてハッシュにキャッシュします。

254
Chuck

違いは、メソッドの使用を実装から分離していることです。プロパティの実装が変更された場合(生年月日を保持し、現在と生年月日の時間差に基づいて年齢を計算するなど)、メソッドに依存するコードを変更する必要はありません。プロパティを直接使用した場合、変更はコードの他の領域に伝播する必要があります。この意味で、プロパティを直接使用することは、クラスが提供するインターフェイスを使用するよりも脆弱です。

23
tvanfosson

Struct.newからクラスを継承する場合は注意が必要です。これは、初期化子を生成する適切な方法です( Rubyで初期化子を生成する方法

class Node < Struct.new(:value)
    def initialize(value)
        @value = value
    end
    def show()
        p @value
        p self.value # or `p value`
    end
end 

n = Node.new(30)
n.show()

戻ります

30
nil

ただし、初期化子を削除すると、戻ります

nil
30

クラス定義付き

class Node2
    attr_accessor :value
    def initialize(value)
        @value = value
    end
    def show()
        p @value
        p self.value
    end
end

コンストラクターを提供する必要があります。

n2 = Node2.new(30)
n2.show()

戻ります

30
30
6
prosseek

違いはありません。私は、それがself.ageおよびother_person.age互いに近い。

Useを使用すると、実際のゲッターを将来記述することができ、インスタンス変数を返すだけでなく、メソッドを変更する必要がなくなるだけでなく、より複雑な処理を行うことができると思います。

しかし、それは、オブジェクトの実装が変更された場合、他のメソッドを変更するのが合理的であるため、心配することはありそうもない抽象化です。ある時点で、オブジェクト自体内の単純な参照は完全に合理的です。

いずれにしても、ageプロパティの抽象化では、selfの明示的な使用については説明されていません。プレーンなageもアクセサーを呼び出したためです。

2
DigitalRoss

最初の答えは完全に正しいですが、相対的な初心者として、それが何を暗示しているのかすぐにはわかりませんでした(メッセージを自己に送信しますか?ええと...)。短い例が役立つと思います:

class CrazyAccessors
  def bar=(val)
    @bar = val - 20 # sets @bar to (input - 20)
  end
  def bar
    @bar
  end

  def baz=(value)
    self.bar = value # goes through `bar=` method, so @bar = (50 - 20)
  end

  def quux=(value)
    @bar = value     # sets @bar directly to 50
  end
end

obj  = CrazyAccessors.new
obj.baz = 50
obj.bar  # => 30
obj.quux = 50
obj.bar  # => 50
1
blob