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)