为什么以下代码中的两种调用方法之间存在差异:
class Access
def method_missing name
print "Method is missing"
end
protected
def protected_method
print "Calling Protected Method"
end
end
access = Access.new
access.protected_method #Method is missing
access.send(:protected_method) #Calling Protected Method
access.protected_method
按预期工作。但是send
选项尝试调用该方法,即使它受到保护。我想知道内部发生了什么。
我得到一个要调用的方法的字符串,所以我想使用send
,但我不想调用受保护的方法。
答案 0 :(得分:6)
这就是send
的工作原理。如果您只想调用公共方法,请使用public_send
。
答案 1 :(得分:1)
使用send可以绕过某些规则,例如访问对象的受保护或私有方法。
另一件事是send允许您动态调用方法。使用send将决定在程序运行之前不知道调用哪些方法,即可以决定在运行时将哪些消息传递给它。
除此之外,据我所知,他们是一样的。
答案 2 :(得分:0)
嗯,这就是send
的工作方式。它允许您调用方法,无论其可见性如何。
如果您发送的是不存在的名称,则method_missing
会启动。请参阅:
class Access
def method_missing name
"Method is missing"
end
protected
def protected_method
"Calling Protected Method"
end
end
access = Access.new
access.protected_method # => "Method is missing"
access.send(:protected_method) # => "Calling Protected Method"
access.send(:non_existing_method) # => "Method is missing"
如果您不希望以这种方式调用受保护的方法,那么,我想,对于可怕的eval
来说,这是一个很好的用例。
eval "Access.new.protected_method" # => "Method is missing"
eval "Access.new.non_existing_method" # => "Method is missing"
答案 3 :(得分:-1)
send
的一个用途是绕过可见性,所以这是一个功能,而不是一个bug,事实上,如果你不允许,你可能会打破使用你的类的其他程序员的期望这种行为。
也就是说,如果您真的需要它,可以覆盖类中的send
和method_missing
来实现您想要的行为:
class Access
def foo; puts "foo"; end
def method_missing(message, *args)
puts "Method #{message} missing"
end
def send(message, *args)
if self.class.protected_instance_methods.include?(message)
method_missing(message, *args)
else
super
end
end
protected
def bar; puts "bar"; end
end
a = Access.new
a.foo #=> 'foo'
a.bar #=> 'Method bar missing'
a.send('bar') #=> 'Method bar missing'