ruby中的一切都是動態的,例如,我們可以在程式執行時,動態的新增方法,類等。前面我們已經看到了ruby的動態特性,例如:給單個物件新增方法,重新開啟類等。
如果熟悉rails,就知道activerecord提供基於資料庫表的欄位名的方法。每乙個欄位都有乙個方法,這個就依賴於ruby的動態特性。
一、單例類的位置
我們可以為乙個物件定義只屬於自己的方法
obj=object.new
def obj.say
puts
"hello world
"end
obj.say #輸出 hello world
那麼單例方法定義在**呢?ruby把單例方法定義在單例類(singleton class)中.每乙個物件實際上都有兩個類:物件呼叫的方法就是定義在這兩個類中的方法,以及祖先類和混含模組中的方法,物件可以呼叫它所屬的類的例項方法,也可以呼叫單例類中的方法。單例類是匿名的,他們是類物件的例項(class類的例項),但他們是自動生成且沒有名字
在方法查詢上,單例方法是最先找到的。str="hello world輸出 "hello world, bye""class
byeself
+", bye
" end
endputs
str.bye
二、eval方法
這個和其它很多語言一樣,具有在執行時執行以字串形式儲存**的的功能。
1.直接執行**
2. 執行時提供方法名的例子
"greeting method:
"m=gets
.chomp
eval
("def #;puts 'hello'; end
")eval
(m)
輸出:hello
如果輸入hi, eval求職的字串是 def hi; puts 'hello'; end
三、eval的危險性
eval很強大,但是它也潛在著危險,這個有點像sql注入
假如,上面我們輸入的不是hi而是下面的內容
hi; endeval求值以後是這樣的; system
("rm -rf /*
"); #
defhi; end
; system
("rm -rf /*
"); # puts 'hello'; end
求值的結果是:#後面的所有內容會被作為注釋忽略掉。使用system命令試圖刪除系統所有檔案
ruby有乙個全域性變數$safe(取值範圍是0到4)、以獲取對如非法寫檔案這一類危險的防護。
四、instance_eval
該方法把self變為instance_eval呼叫的接收者,對字串或**塊進行求職
pself
a=a.instance_eval(p
self
)輸出:
main
instance_eval常用於訪問其它物件的私有資料,特別是例項變數
classc def
initialize
@a=1
endendc=c.new
c.instance_eval
五、class_eval
class_eval可進入類定義體中
c=class.new
c.class_eval do
def some_method
puts
"created in class_eval
" end
endc=c.new
c.some_method
利用class_eval可以訪問外圍作用域的變數。var="test variable"class
c puts
varendc.class_eval
變數var在標準的類定義體的作用域之外,但是在class_eval的**塊的作用域之內當在class_eval的塊中定義乙個例項方法時,又有不同var="test"class
cend
c.class_eval
c.new.hi
# undefined local variable or method `c' for main:object (nameerror)
但我們可以使用另外一種方法c.class_eval }
六、proc物件
pr=proc.new
pr.call
#輸出: hello from inside of proc block
1、做為閉包的proc物件proc物件隨身攜帶了它的上下文,下面上下文包含乙個變數a,該變數被賦值為乙個特殊的字串儲存在proc物件中。像這樣帶著產生它的上下文資訊的一段**被稱為閉包。產生乙個閉包就像是打包一件行李:任何時候開啟行李,都包含打包進去的東西,在開啟乙個閉包時(通過呼叫它),它包含產生
它的時候你放進去的東西。defcall_proc(pr)
a="jack
" puts
a pr.call
enda="tom
"pr=proc
.new
pr.call
call_proc(pr)
#輸出: tom
# jack
# tom
2. proc物件的引數
產生proc物件時所提供的**塊可以接收引數pr=proc.new is better man
"}pr.call("jack
")輸出:jack is better man
七、匿名函式(lambda)
lam=lambdalam.call
輸出: hello world
lambda不是lambda類的物件,他們是proc類的物件lam.class和所有的proc物件一樣,lambda是閉包;他們隨身攜帶了生成他們的區域性的上下文環境輸出: proc
lambda生成的proc物件和用proc.new生成的物件之間的差別與return有關,lambda中的return從lambda返回,而proc中的return從外圍方法返回
deftest_return
l=lambda
l.call
puts
"i am here
" p
=proc
.new
p.call
puts
"bye
"end
test_return
輸出: "i am here
"
八、再論**塊
可以在方法中吧**塊轉換成proc物件,可以通過引數中最後乙個變數,且必須&開頭來捕獲**塊
defsay_block(&block)
block.call
endsay_block
#output: how are you?
def test_block(x,y, &block)
puts
x+yblock.call
endtest_block(1,2)
#output: 3
# hi
也可以將proc物件或lambda轉換為**塊defsay_block(&block)
block.call
endlam=lambda
say_block(&lam)
#output: hello world
一步一步學Ruby 十七 Ruby動態特性
ruby中的一切都是動態的,例如,我們可以在程式執行時,動態的新增方法,類等。前面我們已經看到了ruby的動態特性,例如 給單個物件新增方法,重新開啟類等。如果熟悉rails,就知道activerecord提供基於資料庫表的欄位名的方法。每乙個欄位都有乙個方法,這個就依賴於ruby的動態特性。一 單...
一步一步學Ruby 一 Ruby介紹
文章摘要 ruby是如何來的 ruby 的發明者松本行弘 yukihiro matz matsumoto,混合了他喜歡的語言 perl smalltalk eiffel ada 和 lisp 產生了一種具有函式式及指令程式設計特性的新語言。他常說,他是 試著讓 ruby 更自然,而不是簡單,就像生活...
一步一步學Ruby 一 Ruby介紹
文章摘要 ruby是如何來的 ruby 的發明者松本行弘 yukihiro matz matsumoto,混合了他喜歡的語言 perl smalltalk eiffel ada 和 lisp 產生了一種具有函式式及指令程式設計特性的新語言。他常說,他是 試著讓 ruby 更自然,而不是簡單,就像生活...