4

为什么下面代码中两种调用方法有区别:

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但我不想调用受保护的方法。

4

4 回答 4

6

这就是send工作原理。public_send如果您只想调用公共方法,请改用。

于 2012-09-19T13:13:00.200 回答
1

使用 send 可以绕过一些规则,例如访问对象的受保护或私有方法。

另一件事是 send 允许您动态调用方法。使用 send 您可以决定在程序运行之前不知道调用哪些方法,也就是说,您可以决定在运行时将哪些消息传递给它。

除此之外,据我所知,它们是相同的。

于 2012-09-19T13:00:16.243 回答
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"

如果您不希望以这种方式调用受保护的方法,那么,我想这对于 dreaded 来说是一个很好的用例eval

eval "Access.new.protected_method" # => "Method is missing"
eval "Access.new.non_existing_method" # => "Method is missing"
于 2012-09-19T13:02:23.253 回答
-1

的用途之一send是绕过可见性,所以这是一个特性,而不是错误,事实上,如果你不允许这种行为,你可能会打破其他程序员使用你的类的期望。

也就是说,如果你真的需要它,你可以重写sendmethod_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'
于 2012-09-19T13:06:21.613 回答