iT邦幫忙

DAY 21
0

Ruby女孩:10萬.times { puts "為什麼?" }系列 第 21

Ruby女孩(21):來聽聽類別變數與類別實體變數的自白(?)

昨天我們講完類別方法,今天我們來說明一下類別變數,把昨天的code加一些料,讀讀程式碼看看能不能理解類別變數的作用:

class RubyGirl
  attr_accessor :age
  @@size = 0      #這行是新增加的

  def initialize(ruby_skill=0)
    @ruby_skill = ruby_skill
    @@size += 1      #這行是新增加的
  end

  class << self
    def project(x=1)
      puts "每一個RubyGirl都有 #{x} 個project."
    end
    def size
      @@size
    end
    #上面這三行是新增加的
  end
end

好的有三個部分新增加了,能讀出現在類別變數與類別方法可以幹嘛?實際測試之前,我們先來說明一下何謂類別變數:

何謂類別變數?

以下為『類別變數』的自白XD
1. 我的長相跟實體變數不一樣,實體變數只要背一個@,我要背兩個@@...

@ruby_skill #實體變數
@@size #類別變數

2. 如果需要初始值,我的寫法是寫在類別定義一開始,跟實體變數不一樣(他要被包在initialize方法中)。

class RubyGirl
  @@size = 0 #設定初始值
end

3. 我可以遊走在類別中的任何地方,也就是在實體方法跟類別方法中都可以使用。

class RubyGirl
  @@size = 0   
  def 實體方法
    @@size +=1
  end
  def 類別方法
    @@size
  end
end

好的,認識完類別變數,我們來測試剛剛最前面的方法可以得到什麼吧!我們在一開始宣告了@@size類別變數,並給他初始值為0,然後在initialize實體方法中,加上一行@@size+=1,也就是讓這個類別中的實體物件被製造出來時,都自動讓@@size的值+1,這可以怎樣呢?

RubyGirl.size
=> 0

annie = RubyGirl.new
=> #<RubyGirl:0x007f98ed81d2c8 @ruby_skill=0>

RubyGirl.size
=> 1

linda = RubyGirl.new
=> #<RubyGirl:0x007f98ed82c160 @ruby_skill=0>

RubyGirl.size
=> 2

用這個.size的類別方法,可以知道目前這個類別被建立了多少個物件,酷吧!

還是再複習一下,請注意.size是屬於類別的方法,因此實體物件是不能使用的

annie.size
NoMethodError: undefined method `size' for #<RubyGirl:0x007f98ed81d2c8 @ruby_skill=0>

何謂類別實體變數?

接下來,要來說說容易被混淆的類別實體變數(class instance variable)

以下是類別實體變數的自白:

1. 我長得跟實體變數一模一樣,我也背一個@

2. 我..我活在類別中的任何地方,除了實體方法以外!

所以你可能找到我的地方就在:

class RubyGirl
  @size = 0
  def 實體方法
    ...
    ...
    #沒有@size
  end
  def 類別方法
    @size
  end
end

我們用『類別實體變數』的寫法來改寫剛剛用『類別變數』記錄類別實體個數的程式碼:

class RubyGirl
  attr_accessor :age
  @size = 0      #把類別變數改成類別實體變數
  def initialize(ruby_skill=0)
    @ruby_skill = ruby_skill
  end
  #注意上方實體方法中並沒有出現@size
  
  class << self
    def project(x=1)
      puts "每一個RubyGirl都有 #{x} 個project."
    end
    def new
      @size +=1
      super
    end
    #建立新的RubyGirl物件的類別方法
    #在此方法中使用類別實體變數來記錄個數
    #super一定要加!因為我們不是想要把.new的方法完全取代,我們只是要擴充這個方法,super這個關鍵字可以讓我們成功擴充.new的方法

    def size
      @size      #把類別變數改成類別實體變數
    end
  end
end

ok,上面的程式碼已經將原本使用類別變數的方法全改成類別實體變數了,接下來來測試一下:

RubyGirl.size
=> 0

annie = RubyGirl.new
=> #<RubyGirl:0x007f97b40fa520 @ruby_skill=0>

RubyGirl.size
=> 1

效果與前面的類別變數是一樣的!由於類別實體變數就是類別物件的實體變數我們也可以用先前提到的attr_reader或attr_accessor來替換他們的方法寫法

class RubyGirl
  attr_accessor :age
  @size = 0
  def initialize(ruby_skill=0)
    @ruby_skill = ruby_skill
  end

  class << self
    attr_accessor :size      #這行是新增加的
    def project(x=1)
      puts "每一個RubyGirl都有 #{x} 個project."
    end
    def new
      @size +=1
      super
    end
  end
end

做個小結:

  1. 實體變數被用在實體方法裡
  2. 類別變數被用在類別的任何地方(實體方法裡也可以)
  3. 類別實體變數被用在類別的任何地方,除了實體方法以外
  4. 實體變數跟類別實體變數都背一個@
  5. 類別變數背兩個@@
  6. 實體變數與類別實體變數都可以用attr_accessor的方式改寫

哇,結果今天光是程式碼就佔據好多版面了,明天要來說說公用方法、受保護的方法與私用方法喔,也是非常容易搞混的一環!

=================================================

21天了!

“The only disability in life is a bad attitude. - Matthew Jeffers”


上一篇
Ruby女孩(20):一次弄懂一件事,今天來分清楚實體方法跟類別方法的差異!
下一篇
Ruby女孩(22):公用、受保護、私用方法大亂鬥
系列文
Ruby女孩:10萬.times { puts "為什麼?" }30

1 則留言

0
blackjosh
iT邦見習生 ‧ 2019-02-17 00:09:12

請問類別變數與類別實體變數的資料會被存放多久? 抑或說何時會被清除?? 例如@@size所記錄的資料是否會一直被保留,直到Ruby Girl這個類別被刪除掉?

我要留言

立即登入留言