2013-03-07 28 views
1

我對ruby和編程有所瞭解,並試圖掌握一些關鍵概念。 鑑於我有一個類的狗,具有以下特點。Ruby/Rails:瞭解ruby getter-setter方法和實例

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它如何知道該實例的知名度的價值?在運行時,所有方法都處理完畢,然後該實例總是與當時的值綁定在一起?道歉,如果這沒有意義或我走了。

回答

6

當你

@dog = Dog.new 

你做兩個spearate事

1)創建一個實例變量@dog無論什麼對象的代碼是目前內

2)狗實例化一個新的實例(其所有的方法和屬性),並分配給它一個參考@dog

@狗是一個變量,恰好指向你在那個時候創建​​的Dog實例(類的「實例」,通常與「對象」的含義相同)。你可以設置其他變量來指向同一個實例,在Ruby中,這通常是你傳遞數據的方式。對象包含實例變量,而這些實例變量指向更多的對象。

使用賦值運算符(即「=」),可以將變量指向任何其他對象。

回答您的問題依次是:

當我在主階級和我打電話@ dog.popularity它是如何 知道流行的該實例的價值?

爲了在您的描述和問題中區分類和對象,您必須小心Ruby(以及一般的OO語言)。 Ruby我假設你指的是Owner類中的一行代碼,並且你打算使用owner對象。我還假設@dog是您添加到所有者的屬性。

在這種情況下,Ruby知道是因爲@ Dog指向您添加到所有者的Dog對象。每個Dog對象都有自己的所有Dog實例變量的副本。但是,你確實需要在Ruby中注意,因爲變量指向了對象,你並不是簡單地將同一個Dog對象傳遞給所有的所有者(即它們都有效地共享一條狗)。因此,您需要了解何時創建新實例(通過新建)以及何時處理現有引用。

在運行時是所有的方法處理,然後該實例只是 總是綁在當時的值?

不。在運行時,基本的Ruby只會執行您編碼的賦值。直到分配它們的代碼已經運行,實例變量可能不存在。如果你使用attr_reader等方法,那麼變量至少會存在(但是,除非你在初始化過程中指定了某些東西,否則它們將爲零)

+0

好的,謝謝你非常有幫助。所以在我的例子中,當狗被實例化時,它在初始化和它的所有方法中被賦值。然而,直到應用程序/程序要求它與@ dog.popularity ...類似,流行性方法返回並與該實例關聯的值纔會對方法進行評估?就像我再次調用它會再次處理方法/關聯方法,還是隻知道它以前調用的值? – BC00 2013-03-07 21:15:16

+0

它每次都被處理,它不記得。順便說一下,你通常不需要或者同時需要「attr_accessor:foo」和「def foo」 - 只是一個或另一個。如果你只想讀取和寫入實例變量,那麼attr_accessor是最簡單的。任何更復雜的東西,你想定義一個方法。 – 2013-03-07 21:18:46

+0

真棒謝謝,這給我帶來了很多東西在一起 – BC00 2013-03-07 21:19:50

0

創建對象時,不需要使用@符號。變量是對象。所以,如果你有多個狗,你會怎麼做:

myDog = Dog.new(brown) 
yourDog = Dog.new(white) 

從那裏,你可以說:

yourDog.type #white 
myDog.type #brown 

什麼,你不會做的是:

@dog = Dog.new #myDog 
@dog = Dog.new #yourDog 

如果您需要一個對象的多個版本,你只要給他們不同的名字。所以,如果你創建多個狗並將它們傳遞給其他對象,它們將會工作。例如:

說你的主人類是:

Class Owner 
def initialize(pet) 
    puts "my pet is #{pet.type}" 
end 

然後使用實例變量是:

me = Owner.new(myDog) #my pet is brown 
you = Owner.new(yourDog) #my pet is white 
0

「類型」和「流行度」都是「狗」實例的方法。它們的定義如下:

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它返回它的實例變量; @ dog.popularity在@dog上調用流行度方法,它可以即時進行計算(由您定義)並返回結果。這裏沒有魔法!

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是對象「1」的引用,它是類Fixnum的一個實例。 '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] 

如果你通過這樣的參考方法調用,或到其他類或只是通過自身評價它不要緊 - 紅寶石知道它是一個對象引用,並期待在物體內部和它的繼承鏈如何解決事情。

解析方法名稱

這只是部分真實:)當解釋x.legs,紅寶石檢查是否存在對象的類的繼承鏈的方法,其響應於該名稱「腿」 。 這不是神奇地訪問具有相同名稱的實例變量!

我們可以通過做「attr_reader:legs」或「attr_accessor: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 

沒有神奇的方式實例變量被自動訪問。它們總是通過一種方法訪問,稍後可以覆蓋它。

我希望對你有意義