Ruby 類別變數

written | in ruby | comments

類別變數,有時也稱靜態變數,簡單說就是專屬於類別的變數,不依實體不同而有所差異,類別成員下皆共享的,因為是存在特定的記憶體區塊,所以不會因實體的存活期間所影響。

各個oop語言的類別變數大致的理念都是相同的,用法上可能會略有不同,今次是就來探討ruby的使用狀況。

類別變數種類

ruby的類別變數有區分以下兩種,而兩者都可以被類別方法正常存取與使用,但還是有差異如下:

@@var => Class Variable 類別變數

@var => Class Instance Variable 類別實體變數

主要差異為:

1.@@可以給子類別繼承; @不可以

類別變數繼承
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Parent
  @@blood = :b
  @hobby = :car

  def self.blood
    @@blood
  end

  def self.hobby
    @hobby
  end
end

class Child < Parent
end

Parent.hobby # car
Child.hobby # nil
Parent.blood # b
Child.blodd # b

Child.instance_eval do
  @hobby = :coding
end
Child.hobby # coding

2.@@雖可以被繼承,但由於所有類別都共用,故@@更改後也會影響其他類別所擁有的相同@@;而@因為不會被繼承所以沒這問題

所以使用@@的時候請小心,一般來說較常使用@來當做類別變數

類別變數共享問題
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Parent
  @@blood = :b

  def self.blood
    @@blood
  end

  def self.blood=(value)
    @@blood = value
  end
end

class Child < Parent
end

Parent.blood # b
Child.blood # b
Child.blood = :c
Parent.blood # c
Child.blood # c

3.@@可以給實體方法使用; @不可以

因為@對實體方法的角度來看,會當做實體變數去讀取而非類別實體變數

實體方法使用類別變數
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Parent
  @@blood = :b
  @hobby = :car

  def blood
    @@blood
  end

  def hobby
    @hobby
  end
end

dad = Parent.new
dad.blood # b
dad.hobby # nil

如果實體方法想使用類別實體變數,那就改讓實體方法去呼叫類別方法即可

1
2
3
4
5
6
7
8
9
10
11
12
13
Parent.class_eval do
  def self.hobby
    @hobby
  end

  def get_hobby_by_class_method
    Parent.hobby
  end
end

mom = Parent.new
mom.hobby # nil
mom.get_hobby_by_class_method # car

補充

換種類別方法定義的方式來看更複雜一點的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Animal
  class << self
    @@move = true
    @@breath = "Air"
    @food = %w(meat grass)
    def description
      if @@move
        puts "We Can beathe #{@@breath}"
      end
    end

    def food
      @food ||= []
    end

    def food_list
      @food.each do |food|
        puts "We like #{food}"
      end if @food
    end
  end
end

Animal.description
# We Can beathe Air
# nil
Animal.food_list
# nil
Animal.food << "meat"
Animal.food_list
# We like meat

看來我們無法在class << self的裡面直接定義@的類別實體變數,若非要在該區塊內設定@的類別實體變數,得借用類別方法來完成!


參考

Class Variables and Methods


Comments

blog comments powered by Disqus