1

私はルビーとプログラミング全般に不慣れで、いくつかの重要な概念を理解しようとしています。以下の特性を持つクラス Dog があるとします。

class Dog
  attr_accessor :type, :popularity, :total

  def initialize(type = nil)
    @type = type
  end

  def total_dogs
    Dog.count
  end

  def total
    Dog.where(:type => self.type).size
  end

  def popularity
    total.to_f/total_dogs
  end
end

私が理解しようとしているのは、Ruby が getter/setter メソッドを介してインスタンスに属性を永続化する方法です。新しいインスタンスをインスタンス化してからそのインスタンスに属性を保存すると、オブジェクトを見ると属性が次のように表示されるため、それらの属性がそのインスタンスに関連付けられていることは明らかです。

 @dog = Dog.new
 @dog
 => #<Dog:0x007fa8689ea238 @type=nil> 

@dog オブジェクトを渡すと、常に @type 属性が nil になることを理解するのは簡単です。ただし、この @dog オブジェクトを別のクラスに渡すと、理解に苦しむ状況になります。私がした場合のように:

 Owner.new(@dog)

所有者クラスで @dog.popularity を呼び出すと、そのインスタンスの人気の値をどのように知ることができますか? 実行時にすべてのメソッドが処理され、そのインスタンスは常にその時点の値に関連付けられますか? これが意味をなさない場合、または私がかなり外れている場合はお詫び申し上げます。

4

4 に答える 4

6

あなたがするとき

@dog = Dog.new

あなたは2つの別々のことをします

1)コードが現在内部にあるオブジェクトのインスタンス変数 @dog を作成します

2) Dog の新しいインスタンス (すべてのメソッドと属性を含む) をインスタンス化し、それへの参照を @dog に割り当てます。

@dog は変数であり、その時点で作成した Dog インスタンス (「クラスのインスタンス」は一般に「オブジェクト」と同じ意味) を指しています。同じインスタンスを指すように他の変数を設定できます。Ruby では、これが一般的にデータを渡す方法です。オブジェクトにはインスタンス変数が含まれており、これらのインスタンス変数はさらに多くのオブジェクトを指しています。

代入演算子 (つまり "=") を使用すると、変数を他のオブジェクトに向けることができます。

あなたの質問に順番に答えるには:

所有者クラスで @dog.popularity を呼び出すと、そのインスタンスの人気の値をどのように知ることができますか?

Ruby (および OO 言語全般) では、説明と質問でクラスとオブジェクトを区別するように注意する必要があります。Ruby Owner クラスのコード行を参照していて、それが所有者オブジェクトで動作することを意図していると想定しています。また、@dog は所有者に追加した属性であると仮定します。

その場合、Ruby は @dog が所有者に追加した Dog オブジェクトを指していることを認識しています。各 Dog オブジェクトには、Dog のすべてのインスタンス変数の独自のコピーがあります。ただし、Ruby では注意が必要です。変数はオブジェクトを指すため、単純に同じ Dog オブジェクトをすべての所有者に渡す (つまり、すべての所有者が事実上 1 匹の犬を共有する) わけではありません。そのため、(new を使用して) 新しいインスタンスを作成するときと、単に既存の参照を処理するときを理解する必要があります。

実行時にすべてのメソッドが処理され、そのインスタンスは常にその時点の値に関連付けられますか?

いいえ。基本的な Ruby は実行時に、コーディングした割り当てのみを実行します。インスタンス変数は、それらを割り当てるコードが実行されるまで存在しない場合があります。attr_reader などのメソッドを使用する場合、変数は少なくとも存在します (ただし、初期化中に何かを割り当てない限り、nil になります)

于 2013-03-07T20:59:18.813 に答える
2

ニールはこれについて素晴らしい答えを持っています。私はそれに何かを追加したいだけです.

犬を数える:)

これを行うにはクラス変数が必要です..

class Dog
  @@count = 0     # this is a class variable; all objects created by this class share it

  def initialize
    @@count += 1  # when we create a new Dog, we increment the count
  end
  def total
    @@count
  end
end

「Class オブジェクトのインスタンス変数」でこれを行う別の方法がありますが、それは少し高度なトピックです。

インスタンス変数へのアクセス

Ruby では、変数は実際にはオブジェクト / インスタンスへの参照にすぎません。

 > x = 1
 => 1 
 > x.class
 => Fixnum
  > 1.instance_variables
 => [] 

x は、Fixnum クラスのインスタンスであるオブジェクト '1' への参照です。'1' オブジェクトは、インスタンス変数を含まない Fixnum のインスタンスです。新しい「Dog」インスタンスへの参照と何ら変わりはありません。

x = Dog.new同様に、 x はクラス Dog のインスタンスへの参照であると言えます。

class Dog
  attr_accessor :legs   # this defines the 'legs' and 'legs=' methods!
end

x = Dog.new
x.instance_variables
=> []     # if you would assign legs=4 during "initialize", then it would show up here
x.legs = 4      # this is really a method call(!) to the 'legs' method
x.instance_variables   # get created when they are first assigned a value
 => [:legs] 

そのような参照をメソッド呼び出しに渡すか、別のクラスに渡すか、それ自体で評価するかは問題ではありません。Ruby はそれがオブジェクト参照であることを認識しており、オブジェクトの内部と継承チェーンを調べて問題を解決します。

メソッド名の解決

それは部分的な真実でした:) を解釈するときx.legs、Rubyはオブジェクトのクラス継承チェーンにその名前「legs」に応答するメソッドがあるかどうかをチェックします。同じ名前のインスタンス変数に魔法のようにアクセスしているわけではありません!

「attr_reader :legs」または「attr_accessor :legs」を実行するか、メソッドを自分で定義することにより、「legs」メソッドを定義できます。

class Dog
  def legs
     4     # most dogs have 4 legs, we don't need a variable for that
  end
end

x.legs     # this is a method call! it is not directly accessing a :legs instance variable!
 => 4
x.instance_variables
 => []     # there is no instance variable with name ":legs"

メソッドとインスタンス変数として実装しようとすると、これが起こります: :)

class Dog
   attr_accessor :legs  # this creates "def legs" and "def legs=" methods behind the scenes
   def legs        # here we explicitly override the "def legs" method from the line above.
      4
   end
end

x = Dog.new
x.legs       # that's the method call we implemented explicitly
 => 4
x.legs = 3   # we can still assign something to the instance_variable via legs=
 => 3
x.legs       # the last definition of a method overrides previous definitions
             # e.g. it overrides the automatically generated "legs" method
 => 4 

attr_accessor :legsこれを行うための簡単な表記法は次のとおりです。

class Dog
  def legs
    @legs
  end 
  def legs=(value)
    @legs = value
  end
end

インスタンス変数が自動的にアクセスされる魔法の方法はありません。それらは常にメソッドを介してアクセスされ、後でオーバーライドできます。

それがあなたにとって理にかなっていることを願っています

于 2013-03-07T21:56:06.987 に答える
0

「type」と「popularity」はどちらも「dog」インスタンスのメソッドです。それらの定義は次のとおりです。

class Dog
  # getter
  def type
    @type
  end

  def popularity
    total.to_f/total_dogs
  end
end

これは、次とほぼ同等です。

class Dog
  attr_accessor :type

  def popularity
    total.to_f/total_dogs
  end
end

attr_accessor は、getter メソッドを定義するための単なるショートカットであることに注意してください。自分でメソッドを定義する場合、attr_accessor を使用しても意味がありません。

class Dog
  attr_accessor :popularity

  # this will override getter defined by attr_accessor
  def popularity
    total.to_f/total_dogs
  end
end

質問に戻ります: @dog.type は、インスタンス変数を返す @dog の type メソッドを呼び出します。@dog.popularity は、その場で (ユーザーが定義したように) 計算を行い、結果を返す @dog の人気メソッドを呼び出します。ここに魔法はありません!

于 2013-03-07T21:13:17.010 に答える