Ruby 动态调用方法
本章节我们会讲解学习如何在 Ruby 中如何动态调用方法。
1. 如何动态调用方法
我们使用send
来动态调用方法。
实例:
class Cloud
def rain
p "rain"
end
def hurricane
p "hurricane"
end
end
cloud = Cloud.new
cloud.send(:rain)
cloud.send(:hurricane)
p "====================="
cloud.rain
cloud.hurricane
# ---- 输出结果 ----
"rain"
"hurricane"
"###################"
"rain"
"hurricane"
解释:
在此示例中,我们定义了一个具有两个方法的类,然后使用send
方法调用了每个方法。为了进行比较,我们还使用点运算符(.
)以通常的方式调用了相同的方法。
**注意事项:**方法名的类型通常使用Symbol
,字符串也没有问题。
cloud = Cloud.new
cloud.send(:rain)
cloud.send(:hurricane)
p "====================="
cloud.send("rain")
cloud.send("hurricane")
"rain"
"hurricane"
"rain"
"hurricane"
2. 动态调用方法传递参数
2.1 传递往常一样的参数
要使用send
将参数发送给方法,我们需要在方法名称后指定参数。我们可以放多少东西没有限制。
实例:
class ParametersTest
def method_with_positional_parameter(a)
p a
end
def method_with_few_positional_parameters(a,b,c)
p a,b,c
end
def method_with_infinity_args(*a)
p a
end
def method_with_keyword_parameter(keyword_parameter:)
p keyword_parameter
end
end
test = ParametersTest.new
test.send(:method_with_positional_parameter, "Hello!")
test.send(:method_with_few_positional_parameters, "Hi!", "Hello!", "Hola!")
test.send(:method_with_infinity_args, "first", "second", "third")
test.send(:method_with_keyword_parameter, keyword_parameter: "keywooord parameter")
# ---- 输出结果 ----
"Hello!"
"Hi!"
"Hello!"
"Hola!"
["first", "second", "third"]
"keywooord parameter"
我们可以看到,传递块没有什么区别,在两种情况下,我们收到的结果都是相同的。
2.2 传递一个block
实例:
class Cloud
def rain
p "rain"
yield
end
def hurricane
p "hurricane"
yield
end
end
cloud = Cloud.new
cloud.send(:rain) { p "It's raining! "}
cloud.send(:hurricane) { p "Wow! I better stay home today!"}
p "###################"
cloud.rain { p "It's raining! "}
cloud.hurricane { p "Wow! I better stay home today!"}
# ---- 输出结果 ----
"rain"
"It's raining! "
"hurricane"
"Wow! I better stay home today!"
"###################"
"rain"
"It's raining! "
"hurricane"
"Wow! I better stay home today!"
传递参数的方式非常明显,方法调用的结构变化不大。
注意事项:
如果方法名称指定不正确,我们将看到一个异常。
实例:
class ExampleClass
def method_name
end
end
instance = ExampleClass.new
instance.send(:method_method_name)
# ---- 输出结果 ----
NoMethodError: undefined method `method_method_name' for #<ExampleClass:0x0000000194ff10>
Did you mean? method_name
from (irb):34
from /usr/bin/irb:11:in `<main>'
3. 动态调用方法的实例
当我们想一次调用多个方法时,最适合使用send
方法。
想象一下,我们拥有一些包含许多不同引擎的技术,我们需要启动每个引擎。
实例:
class SomeTechnology
def turn_on
lower_engine
upper_engine
left_upper_engine
right_upper_engine
end
private
def lower_engine
p "lower engine wroom wooom"
end
def upper_engine
p "upper engine wroom wroom"
end
def left_upper_engine
p "left upper engine wroooooom"
end
def right_upper_engine
p "right upper engine wroooooom"
end
end
我们可以注意到,首先是所有方法名称中都有一个通用词“ engine”。第二个问题是,如果方法数量增加,我们将不得不扩展turn_on
方法。
class SomeTechnology
ENGINES = [:lower, :upper, :left_upper, :right_upper]
def turn_on
ENGINES.each do |name|
send("#{name}_engine")
end
end
private
def lower_engine
p "lower engine wroom wooom"
end
def upper_engine
p "upper engine wroom wroom"
end
def left_upper_engine
p "left upper engine wroooooom"
end
def right_upper_engine
p "right upper engine wroooooom"
end
end
tech = SomeTechnology.new
tech.turn_on
# ---- 输出结果 ---
"lower engine wroom wooom"
"upper engine wroom wroom"
"left upper engine wroooooom"
"right upper engine wroooooom"
这样我们代码的扩展性就变得高了。
4. 小结
本章中我们学习了:
-
send
方法在Object
类中定义作为参数,我们可以传递字符串或字符。 -
我们可以传递一个块,就像通常的方法调用一样。
-
我们也可以像往常一样传递所有相同的参数。
-
如果方法名称指定不正确,我们将看到一个异常。
-
当我们动态获取方法名称时,此方法非常理想。
-
当我们想一次调用多个方法时,
send
方法是合适的。