self上下文
Ruby的self有和Java的this相似之處,但又大不相同。Java的方法都是在執行個體方法中引用,所以this一般都是指向當前對象的。而Ruby的代碼逐行執行,所以在不同的上下文(context)self就有了不同的含義,先來看看常見的context self都代表哪些
# 這個位置位於top level context,代表Object的預設對象main
p self # => main
p self.class # => Object
@self1 = self
# 因為所有自訂類都位於main context之中,所以這是Object的執行個體方法
# 同時也可以說是一個全域方法
def a_method
@self2 = self
p self
# => main,因為有了執行個體變數@self1和@self2,所以列印出來的不是main這個字元
# => 但仍然是main對象,注釋掉4,8行即可看到效果
p @self1 == @self2 # => true
end
# 下面是一個關於類中不同內容相關的self
class Person
p self # => Person,代表當前類
def instance_method
p self # => #<Person:0xb7818fdc>,代表當前類的執行個體
end
def self.class_method
p self # => Person,和第16行一樣代表當前類(這是類方法的context),它們是相等的
end
end
m = Person.new
def m.hello
p self # => 代表m這個單例對象
end
m.hello
上面唯寫了在類中的self,其實在module也是一樣的。通過上面代碼你可以發現,self一直引用著它所在位置內容相關的執行個體/類。
self顯式/隱式
你可以先試著運行下面代碼,看看有什麼意外發生沒有
class Person
attr_accessor :name
def set_name(your_name)
name = your_name
end
end
m = Person.new
p m.name
m.set_name('today')
p m.name # => 猜是什麼
如果你猜是today就大錯特錯了,答案是nil,為什麼是nil呢,在第5行,我明明調用的是attr_accessor產生的name=方法賦值的啊,你可以在前面加上self試試,代碼如你預期的一樣執行了。在這種情況下name = your_name並沒有去調用attr_accessor產生的xx=方法,而是將name當作了一個局部變數,如果顯式的指定self,就沒有問題了。
讀到這,你是不是認為以後這種情況就一直用顯式self去調用就好了,其實不然,下面的代碼仍會說明一些問題
class Person
public
def get_my_secret1
my_secret # => 隱式
end
def get_my_secret2
self.my_secret # => 顯式
end
private
def my_secret
p 'something...'
end
def self.secret
p 'nothing'
end
end
m = Person.new
#m.my_secret # => private method error
Person.secret # => nothing
m.get_my_secret1 # => something
m.get_my_secret2 # => private method error
上面代碼說明:
第一個問題,顯式self不可以調用private(protected的也一樣)方法,而隱式的可以,這說明隱式更具有靈活性,但由於上面隱式調用也同時存在一定的“誤解”,所以讀者應該明白他們之間的區別,以便更好的使用。
第二個問題,self的方法不受private限制,其實我在這故意誤導了讀者,因為self的方法是類方法,而許可權修飾符只對執行個體方法生效,所以private的類方法也可以直接存取。
self“怪異”寫法
下面代碼被我個人稱為怪異寫法,因為平時用不到,但偶爾會看到,但看起來又不太直觀,這裡列舉一下
class Person
def metaclass
class << self
self
end
end
def metaclass2
self
end
end
a = Person.new
b = a.metaclass
c = a.metaclass2
# 首先要明白,類Person是Class的一個“執行個體”,a是Person的一個執行個體
# 這裡b也是一個Person類,但它是獨一無二的,即你修改Person不會影響到b,反之亦然
p b # => #<Class:#<Person:0xb76f3800>>
p b.class # => Class
class Person
def hello
p 'hello Person'
end
end
class << b
def hello
p 'hello b'
end
end
b.hello # => hello b
p c # => #<Person:0xb76f3800>
p c.class # => Person
c.hello # => hello Person
還有一個
class Person
def self.hello
p 'hello'
end
class << self
# 看了最上面self和context的關係,你應該知道這個self代表是Person類
# 在這裡為Person添加方法,其實也就是為Person添加類方法,和上面的self.hello異曲同工
def work
p 'hard work'
end
end
end
Person.work
轉自:http://ilstar.blogbus.com/logs/59782933.html