動(dòng)態(tài)處理各種類型變量
之前的章節(jié)中我們學(xué)習(xí)了 Ruby 中一共有局部、實(shí)例、類、全局 4 種變量,以及一種常量,今天讓我們來(lái)學(xué)習(xí)一下在元編程中,如何動(dòng)態(tài)獲取這些變量。
1. 局部變量
局部變量以往我們使用eval
來(lái)獲取。
實(shí)例:
b = binding
(1..3).each do |num|
b.eval("a_#{num} = #{num}")
end
(1..3).each do |num|
puts b.eval("a_#{num}")
end
# ---- 輸出結(jié)果 ----
1
2
3
Tips:
binding
是獲取所處在的作用域的方法。
解釋:因?yàn)?code>each后面有一個(gè) block,兩個(gè) block 里面的作用域不共享(詳細(xì)在作用域章節(jié)中會(huì)學(xué)習(xí)到),這里我們用了binding
,讓eval
可以共享頂級(jí)作用域。分別動(dòng)態(tài)定義了 a_1~a_3 的方法,并動(dòng)態(tài)輸出出來(lái)。
在 Ruby 2.1.0 之后,增加了local_variable_set
、和local_variable_get
方法。
實(shí)例:
b = binding
(1..3).each do |num|
b.local_variable_set("a_#{num}".to_sym, num)
end
(1..3).each do |num|
puts b.local_variable_get("a_#{num}".to_sym)
end
# ---- 輸出結(jié)果 ----
1
2
3
它們本質(zhì)上是相同的。
2. 實(shí)例變量
同樣我們可以使用eval
來(lái)獲取,只需要在局部變量前加一個(gè)@
,本著少使用eval
的原則,這里我只給大家講解我們更常用的instance_variable_set
和instance_variable_get
。
實(shí)例:
class Person
def initialize
(1..3).each do |num|
instance_variable_set("@name_#{num}".to_sym, num)
end
end
(1..3).each do |num|
define_method "name_#{num}".to_sym do
instance_variable_get("@name_#{num}".to_sym)
end
end
end
person = Person.new
p person.name_1
p person.name_2
p person.name_3
# ---- 輸出結(jié)果 ----
1
2
3
解釋:在類被定義的時(shí)候,動(dòng)態(tài)創(chuàng)建3個(gè)方法:name_1
、name_2
、name_3
,分別返回實(shí)例變量@name_1
、@name_2
、@name_3
。在類被實(shí)例化的時(shí)候,動(dòng)態(tài)增加了三個(gè)實(shí)例變量@name_1
,@name_2
,@name_3
,并賦予1、2、3的初值。
3. 類變量
動(dòng)態(tài)設(shè)置類變量所使用到的方法為:class_variable_set
和class_variable_get
。
實(shí)例:
class Person
(1..3).each do |num|
class_variable_set("@@name_#{num}".to_sym, num * 3)
end
def initialize
(1..3).each do |num|
instance_variable_set("@name_#{num}".to_sym, self.class.class_variable_get("@@name_#{num}".to_sym))
end
end
(1..3).each do |num|
define_method "name_#{num}".to_sym do
instance_variable_get("@name_#{num}".to_sym)
end
end
end
person = Person.new
p person.name_1
p person.name_2
p person.name_3
# ---- 輸出結(jié)果 ----
3
6
9
解釋:這次我們?cè)陬惓跏蓟臅r(shí)候創(chuàng)建了@@name_1
、@@name_2
、@@name_3
三個(gè)變量賦予3、6、9三個(gè)初值。在類實(shí)例化的時(shí)候使用類變量分別對(duì)@name_1
、@name_2
、@name_3
進(jìn)行初始化。注意這里class_variable_get
是類方法,所以要使用self.class
來(lái)獲取。
4. 全局變量
可以使用eval
,但是不建議這樣做,因?yàn)榉浅ky以調(diào)試和維護(hù)這些全局變量。
5. 常量
動(dòng)態(tài)操作常量我們使用const_get
和const_set
兩個(gè)方法。
module Test
(1..3).each do |num|
const_set "CONSTANT_#{num}", num
end
(1..3).each do |num|
const_set "CONSTANT_#{num}"
end
end
# ---- 輸出結(jié)果 ----
1
2
3
注意事項(xiàng):const_get
和const_set
這兩個(gè)方法要放在module
里面才可以使用。另外不要對(duì)常量進(jìn)行重復(fù)賦值。
6. 小結(jié)
本章節(jié)我們學(xué)習(xí)了:
- 局部變量使用
local_variable_set
和local_variable_get
; - 實(shí)例變量使用
instance_variable_set
和instance_variable_get
; - 類變量使用
class_variable_set
和class_variable_get
; - 常量使用
const_set
和const_get
; - 全局變量不建議動(dòng)態(tài)創(chuàng)建和調(diào)用;
- 所有動(dòng)態(tài)處理變量都可以使用
eval
,但是不推薦使用。