1.方法的動態(tài)調(diào)用
為何Ruby如此先進(jìn),為何它元編程能力這么強(qiáng)大嘉蕾,得益于它能夠運(yùn)行時生成需要的代碼,或者調(diào)用相應(yīng)的方法霜旧。這樣的特性給Ruby程序增加了不少的靈活性错忱。(好了,我當(dāng)然知道Python也有類似的東西)這里我們看看Ruby是如何優(yōu)雅地動態(tài)調(diào)用方法挂据。
[1] pry(main)> class MyClass
[1] pry(main)* def my_method(my_arg)
[1] pry(main)* my_arg * 2
[1] pry(main)* end
[1] pry(main)* end
=> nil
[2] pry(main)> obj = MyClass.new
=> #<MyClass:0x007fec79b94b10>
[3] pry(main)> obj.send(:my_method, 3)
=> 6
為了方便我就直接在pry
交互環(huán)境里面定義一個類MyClass
以清,并創(chuàng)建該類的一個對象obj
。最后我們通過一個send
方法來調(diào)用函數(shù)崎逃,而沒有用對象.方法
的方式來調(diào)用掷倔。這種調(diào)用函數(shù)的方式叫做動態(tài)指派
。
其實(shí)這種方式更加清晰說明調(diào)用方法的概念: 調(diào)用一個方法實(shí)際上就是給對象發(fā)送一條消息
這里可以看成我們給obj
對象send
一個消息my_method
以及參數(shù)3
个绍。
很多人可能有疑問勒葱,這里的:my_method
是什么鬼。
這里得說一下巴柿,它是Ruby的內(nèi)置類型凛虽,叫做符號,它跟Ruby的字符串的用法其實(shí)是差不多的广恢。每個字符串都有它對應(yīng)的符號
[4] pry(main)> "lanzhiheng".class
=> String
[5] pry(main)> :lanzhiheng.class
=> Symbol
[10] pry(main)> "lanzhiheng".to_sym
=> :lanzhiheng
[11] pry(main)> :lanzhiheng.to_s
=> "lanzhiheng"
只是我們應(yīng)該還記得凯旋,Ruby里面字符串是可變的
。而我們這里提到的符號是不可變的钉迷。因此符號更加適合表示方法名至非。當(dāng)然,這里用字符串來表示也是沒問題的糠聪。
[12] pry(main)> obj.send("my_method", 2)
=> 4
不過我們還是遵守社區(qū)的建議荒椭,用符號來表示這一類值吧,而且也有人說舰蟆,Ruby中使用符號會相比字符串更加節(jié)省空間趣惠,運(yùn)行速度會更快一些
。
2.動態(tài)方法的定義
這里不得不提到一個很優(yōu)雅的動態(tài)定義方法的語法夭苗, 這里我們就不偷懶了信卡,我在腳本上寫下面的邏輯。
class MyClass
define_method :my_method do |my_arg|
my_arg * 3
end
end
obj = MyClass.new
p obj.my_method(3)
由運(yùn)行結(jié)果9
可以看出我們的方法是定義成功了题造。這里的define_method
方法能夠很方便地定義我們需要的方法傍菇。總的來說它接收兩個參數(shù), 1. 函數(shù)名界赔。2. 方法體(這里是通過代碼塊
的方式定義的)
借助這種方式我們可以通過類似工廠的方式來產(chǎn)出許多方法名不同而它們的方法體卻有一定規(guī)律的方法丢习。在一定程度上牵触,減少了不必要的代碼量。如下:
["hello", "hi", "say"].each do |name|
define_method "#{name}_define" do
name
end
end
p hello_define
p hi_define
p say_define
結(jié)果是:
"hello"
"hi"
"say"
之前還聽到有些同行吐槽說不喜歡Ruby的代碼塊咐低,說是不夠優(yōu)雅揽思,但是我是比較喜歡這種方式。不知道您怎么想见擦。-_-
3.幽靈方法
這里最最最得說一下的就是幽靈方法钉汗。
幽靈方法的方法名是method_missing
,看名字就很霸氣鲤屡,它相當(dāng)于一個鉤子损痰。當(dāng)你調(diào)用的方法不存在的時候就會調(diào)用這個方法。舉個栗子看看酒来。
class MyClass
def method_missing(method, *args)
"The method #{method} with you call not exists"
end
end
obj = MyClass.new
p obj.hello_world("becase")
打印的結(jié)果是
"The method hello_world with you call not exists"
這在正常情況下是會報錯的卢未,如今卻能夠利用幽靈方法
給出那么優(yōu)雅的消息提示。
然而, 這種方式有什么用? 我們可以用幽靈方法來做一些東西堰汉。我舉個最簡單的例子辽社,當(dāng)然實(shí)際例子會復(fù)雜很多。
class Proxy
def method_missing(method, *args)
MyClass.send(method, *args)
end
end
class MyClass
def self.user
"Ruby"
end
def self.password
"RubyOnRails"
end
end
proxy = Proxy.new
p proxy.user
p proxy.password
這里我們Proxy
類對象的幽靈方法會調(diào)用MyClass
類的類方法user
and password
翘鸭。這里如果我們MyClass
添加新的方法滴铅,而我們需要利用Proxy
類去訪問的話,則不需要修改Proxy
類里面的任何代碼矮固。我們只需要像平常那樣去調(diào)用就行失息。幽靈方法會幫我們代理到MyClass
那里去譬淳。這種方式稱作動態(tài)代理
档址。這非常有助于我們編寫更加簡約的代碼。
不過上面這些奇怪的東西邻梆,多元化的編碼方式守伸,使得Ruby這門語言開發(fā)的項(xiàng)目相對于Python語言開發(fā)的項(xiàng)目門檻高了不少。不過這也是Ruby吸引人的地方不是嗎浦妄?
今天就到這里吧尼摹。