Ruby 方法instance_eval() 和send() 是否否定了私有可见性的好处?
w = Widget.new # Create a Widget
w.send :utility_method # Invoke private method!
w.instance_eval { utility_method } # Another way to invoke it
w.instance_eval { @x } # Read instance variable of w
查看上面与 Widget 类(如下)相关的示例,send 和 instance_eval 方法违反了私有和受保护可见性提供的所有保护。 如果是这样,为什么要费心在 Ruby 中进行私有和受保护的访问,因为无法保证您的定义会得到遵守?
class Widget
def x # Accessor method for @x
@x
end
protected :x # Make it protected
def utility_method # Define a method
nil
end
private :utility_method # And make it private
end
w = Widget.new # Create a Widget
w.send :utility_method # Invoke private method!
w.instance_eval { utility_method } # Another way to invoke it
w.instance_eval { @x } # Read instance variable of w
Looking at the example above which relates to the Widget class (below), the send and instance_eval methods violate all of the protections provided by private and protected visibility. If so, why bother with private and protected access in Ruby at all since there is no guarantee that your definitions will be honored?
class Widget
def x # Accessor method for @x
@x
end
protected :x # Make it protected
def utility_method # Define a method
nil
end
private :utility_method # And make it private
end
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
ruby 相信赋予您做您想做的事情的能力。 它只是不容易不经意地开枪——如果你想破坏私有声明,你必须使用明确你正在这样做的语法。 请注意,最终决定代码应该或不应该做什么的人是使用库的人,而不是编写库的人。
ruby believes in giving you the power to do what you want. it just doesn't make it easy to inadvertently shoot your foot off - if you want to subvert the private declarations, you have to use syntax that makes it clear you are doing so. note that the person finally deciding what the code should or shouldn't do is the person using a library, not the person writing it.
我无法发表评论,因为代表较低:/。
重新定义send是没有用的,因为send只是__send__的俗称(即下划线,下划线,“发送”,下划线,下划线),这才是真正实现消息发送的方法。 不建议重新定义任何__method__。 此外,其他人还可以重新打开类并恢复定义:
在 Ruby 1.9 中,行为略有不同:#send 实际上尊重可见性,而 __send__ 则不然。
Ruby 中的 private 更多地具有声明性目的:声明为 private 的方法是实现细节,而不是 API 细节。 不允许您意外地从外部发送消息。 但如果他们认为合适的话,任何人仍然可以以自己的名义强行规避这一限制。
I cannot comment, because of low rep :/.
Redefining send is no use, because send is just the common name for __send__ (thats underscore,underscore,"send",underscore,underscore), which is the method actually implementing message sending. Redefining any __method__ is not recommended. Additionally, the other person can also reopen the class and revert the definition:
In Ruby 1.9, the behaviour is slightly different: #send actually honors visibility, __send__ doesn't.
private in Ruby has more of a declarative purpose: methods declared as private are an implementation detail and not an API detail. You are not allowed to send a message from the outside by accident. But anyone can still forcefully circumvent that restriction, if they see fit - on their own account.
如果您确实想要保护
Widget
的实例,您可以执行此操作(以及一堆其他内容;这里的代码不是完整的安全解决方案,仅供参考):If you really want to protect instances of
Widget
, you can do this (and a bunch of other stuff; the code here is not a complete security solution, merely indicative):至少你表达了 Widget 类的公共 API 是什么。
At the very least you express what the public API of the Widget class is.
带回家的信息是:别打扰。
Ruby 和 Python 一样,在沙箱方面绝对很糟糕。 如果你试图锁定某些东西,很可能总会有某种方法来绕过它。 在 Ruby 中获取私有属性的多种方法证明了我的观点。
为什么? 因为它们就是被设计成这样的。 这两种语言都被设计成可以在运行时使用——这就是它们的强大之处。 通过封闭您的类,您就剥夺了其他人 Ruby 元编程提供的功能。
Java有反射。 C++ 有指针。 甚至 Haskell 也有 unsafePerformIO。 如果你想保护你的程序,你需要在操作系统级别保护它,而不是使用语言。
The take home message is: don't bother.
Ruby, like Python, absolutely sucks at sandboxing. If you try to lock something down, chances are there will always be some way to get around it. The multitude of ways to get a private attribute in Ruby proves my point.
Why? Because they are designed to be that way. Both languages are designed so that they can be poked around with at runtime – it's what gives them their power. By sealing up your class, you're depriving others of the power that Ruby's metaprogramming provides.
Java has reflection. C++ has pointers. Even Haskell has unsafePerformIO. If you want to protect your program, you will need to protect it on the operating system level, not using the language.