動態處理各種類型變量
之前的章節中我們學習了 Ruby 中一共有局部、實例、類、全局 4 種變量,以及一種常量,今天讓我們來學習一下在元編程中,如何動態獲取這些變量。
1. 局部變量
局部變量以往我們使用eval
來獲取。
實例:
b = binding
(1..3).each do |num|
b.eval("a_#{num} = #{num}")
end
(1..3).each do |num|
puts b.eval("a_#{num}")
end
# ---- 輸出結果 ----
1
2
3
Tips:
binding
是獲取所處在的作用域的方法。
解釋:因為each
后面有一個 block,兩個 block 里面的作用域不共享(詳細在作用域章節中會學習到),這里我們用了binding
,讓eval
可以共享頂級作用域。分別動態定義了 a_1~a_3 的方法,并動態輸出出來。
在 Ruby 2.1.0 之后,增加了local_variable_set
、和local_variable_get
方法。
實例:
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
# ---- 輸出結果 ----
1
2
3
它們本質上是相同的。
2. 實例變量
同樣我們可以使用eval
來獲取,只需要在局部變量前加一個@
,本著少使用eval
的原則,這里我只給大家講解我們更常用的instance_variable_set
和instance_variable_get
。
實例:
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
# ---- 輸出結果 ----
1
2
3
解釋:在類被定義的時候,動態創建3個方法:name_1
、name_2
、name_3
,分別返回實例變量@name_1
、@name_2
、@name_3
。在類被實例化的時候,動態增加了三個實例變量@name_1
,@name_2
,@name_3
,并賦予1、2、3的初值。
3. 類變量
動態設置類變量所使用到的方法為:class_variable_set
和class_variable_get
。
實例:
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
# ---- 輸出結果 ----
3
6
9
解釋:這次我們在類初始化的時候創建了@@name_1
、@@name_2
、@@name_3
三個變量賦予3、6、9三個初值。在類實例化的時候使用類變量分別對@name_1
、@name_2
、@name_3
進行初始化。注意這里class_variable_get
是類方法,所以要使用self.class
來獲取。
4. 全局變量
可以使用eval
,但是不建議這樣做,因為非常難以調試和維護這些全局變量。
5. 常量
動態操作常量我們使用const_get
和const_set
兩個方法。
module Test
(1..3).each do |num|
const_set "CONSTANT_#{num}", num
end
(1..3).each do |num|
const_set "CONSTANT_#{num}"
end
end
# ---- 輸出結果 ----
1
2
3
注意事項:const_get
和const_set
這兩個方法要放在module
里面才可以使用。另外不要對常量進行重復賦值。
6. 小結
本章節我們學習了:
- 局部變量使用
local_variable_set
和local_variable_get
; - 實例變量使用
instance_variable_set
和instance_variable_get
; - 類變量使用
class_variable_set
和class_variable_get
; - 常量使用
const_set
和const_get
; - 全局變量不建議動態創建和調用;
- 所有動態處理變量都可以使用
eval
,但是不推薦使用。