ruby元編程 第二章 對象模型

2.1 打開類

class D
  def x; 'x'; end
end

class D
  def y; 'y'; end
end

obj = D.new
obj.x  # => "x"
obj.y  # => "y"	

當第一次提及 class D時,Ruby開始定義這個類,並定義x方法。
第二次提及D類時,它已經存在,Ruby就不在定義了,而只是重新打開這個已經存在的類,併爲之定義y方法

ruby的class關鍵字更像是一個作用域操作符,而不是類型聲明語句。

打開類的陰暗面:
如果粗心地爲某個類添加了新功能,就可能無意中覆蓋了原有的功能,這種方式稱之爲猴子補丁

2.2 類的真相

實例變量
class MyClass
  def my_method
    @v = 1
  end
end

obj = MyClass.new
obj.instance_variables # => []

obj.my_method
obj.instance_variables # => [:@v]

與java這樣的靜態語言不同,ruby中對象的類和它的實例變量沒有關係
可以把ruby中實例變量的名字和值理解爲哈希表中的鍵值對,每一個對象的鍵值對都可能不同

方法
obj.methods.grep(/my/) # => [:my_method]

String.instance_methods == "abc".methods # => true

String.methods == "abc".methods # => false

一個對象的實例變量存在於對象本身之中,而一個對象的方法存在於對象自身的類中。

類本身也是對象
"hello".class # => String
String.class # => Class

類像其他對象一樣,也有自己的類,它的名字叫Class

ruby的類繼承自它的超類

Array.superclass # => Object

Object.superclass # => BasicObject

BasicObject.superclass # => nil

Class.superclass  # => Module

Array類繼承自object類, 換句話說, “數組是對象”

Object類中有大多數對象都需要的方法,比如 to_s方法

BasicObject是ruby對象體系中的根節點

Class類的超類是module, 也就是說每一個類都是一個模塊。準確的說,類就是帶有三個方法(new、allocate、superclass)的增強模塊

#false表示忽略繼承的方法
Class.instance_methods(false) # => [:new, :allocate, :superclass]

類與模塊太接近了,保留這個概念的主要原因是爲了獲得代碼的清晰性,讓代碼的意圖更加明確

如果你希望吧自己的代碼包含到別的代碼中,就應該使用模塊;如果你希望某段代碼被實例化或者被繼承,就應該使用類

類不過是對象而已,類名也無非就是常量

2.3 常量

任何以大寫字母開頭的引用(包括類名和模塊名)都是常量
ruby中常量類似於變量,你可以修改常量的值。甚至可以修改String的類名

常量和變量最大的區別在於它們的作用域不同

module MyModule
  MyConstant = 'Outer constant'

  class MyClass
    MyConstant = 'Inner constant'
  end
end

MyModule::MyConstant # => "Outer constant"
MyModule::MyClass::MyConstant # => "Inner constant"

模塊和類就像是目錄,而常量則像是文件。像文件系統一樣,只要不在同一個目錄下,不同文件可以有相同的文件名。我們也可以像文件系統一樣用路徑來引用一個常量

Rake是流行的ruby構建系統 它的最初版本定義了一些常見的類名,例如Task和FileTask

這些類名與其他類庫中的類名相沖突的概率很大,爲了防止命名衝突,最近的Rake版本中把類定義在名爲Rake的模塊中

module Rake
  class Task
    #.....

像Rake這樣只是用來充當常量容器的模塊,被稱爲命名空間

2.4調用方法時發生了什麼

Kernel模塊

Ruby 中有一些方法(如print)可以隨時調用。
這些方法實際上都是Kernel模塊的私有實例方法
Object類包含了Kernel模塊

self關鍵字

當前對象可以用self表示

class MyClass
  def test_self
    @var = 10
    my_method()
    self
  end

  def my_method
    @var = @var + 1
  end
end

obj = MyClass.new
obj.test_self # => #<MyClass:0x00007fa73508b950 @var=11>
private關鍵字

私有方法服從一條簡單的規則:不能明確指定接受者來調用私有方法

class C
  def public_method
    self.private_method
  end

  private
  
  def private_method; end
end

C.new.public_method # => private method `private_method' called for #<C:0x00007fa5178d7e08> (NoMethodError)

去掉self關鍵字就能運行

私有方法只能通過隱形的接受者調用。
你只能在自身中調用私有方法

另外,可以調用從超類中繼承來的私有方法,因爲調用繼承來的方法不用明確指明接受者

細化
module StringExtensions
  refine String do
    def reverse
      "esrever"
    end
  end
end

module StringStuff
  using StringExtensions
  "my_string".reverse # => "esrever"
end

"my_string".reverse # => ""gnirts_ym""

代碼爲String類細化了一個reverse方法,與打開類不同,細化在默認情況下並不生效,爲了使其生效,必須調用using方法

從ruby2.1開始,你可以在一個模塊內部調用using,這樣,細化的作用範圍只在該模塊內部有效

細化只在兩種場合有效:
1.refine代碼塊內部
2.從using語句的位置開始到模塊結束,或者到文件結束(如果是在頂層上下文中調用using)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章