一步一步學Ruby 十七 Ruby動態特性

2021-08-23 15:00:23 字數 4885 閱讀 2646

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

"class

byeself

+", bye

" end

endputs

str.bye

輸出 "hello world, bye"

在方法查詢上,單例方法是最先找到的。

二、eval方法

這個和其它很多語言一樣,具有在執行時執行以字串形式儲存**的的功能。

1.直接執行**

2. 執行時提供方法名的例子

print

"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; end

; system

("rm -rf /*

"); #

eval求值以後是這樣的

def

hi; end

; system

("rm -rf /*

"); # puts 'hello'; end

求值的結果是:#後面的所有內容會被作為注釋忽略掉。使用system命令試圖刪除系統所有檔案

ruby有乙個全域性變數$safe(取值範圍是0到4)、以獲取對如非法寫檔案這一類危險的防護。

四、instance_eval

該方法把self變為instance_eval呼叫的接收者,對字串或**塊進行求職

p

self

a=a.instance_eval(p

self

)輸出:

main

instance_eval常用於訪問其它物件的私有資料,特別是例項變數
class

c 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物件中。像這樣帶著產生它的上下文資訊的

一段**被稱為閉包。產生乙個閉包就像是打包一件行李:任何時候開啟行李,都包含打包進去的東西,在開啟乙個閉包時(通過呼叫它),

它包含產生

它的時候你放進去的東西。

def

call_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=lambda 

lam.call

輸出: hello world

lambda不是lambda類的物件,他們是proc類的物件
lam.class

輸出: proc

和所有的proc物件一樣,lambda是閉包;他們隨身攜帶了生成他們的區域性的上下文環境

lambda生成的proc物件和用proc.new生成的物件之間的差別與return有關,lambda中的return從lambda返回,而proc中的return從外圍方法返回

def

test_return

l=lambda

l.call

puts

"i am here

" p

=proc

.new

p.call

puts

"bye

"end

test_return

輸出: "i am here

"

八、再論**塊
可以在方法中吧**塊轉換成proc物件,可以通過引數中最後乙個變數,且必須&開頭來捕獲**塊
def

say_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轉換為**塊
def

say_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 更自然,而不是簡單,就像生活...