我一直有这个烦人的反复出现的主题;我只想说,我有一个定义实例方法和受保护类方法的类。实例方法必须调用类方法。为了做到这一点,我必须打破可见性规则并使用危险的“发送”功能。像这样:
class Bang
def instance_bang
self.class.send(:class_band)
end
protected
def self.class_bang
puts "bang"
end
end
我发现这很糟糕,因为类方法应该在类范围内使用,因此应该在其中保持可见和可调用,对吧?是否有另一种方法在实例方法中使用类方法,需要依赖“发送”功能,因此不会破坏可见性?
更新:
根据Sergio Tulentsev的回复(thx进行更正),我将更新我对一个代码片段的关注,该代码片段总结了我对方法可见性的关注,同时仍然在已经定义的范围内。
class Bang
def instance_bang
private_bang = 1
self.private_bang(private_bang)
end
private
def private_bang(p)
puts "bang"
p
end
end
调用Bang.new.instance_bang将引发异常,除非您在该private_bang调用上使用send(这次我检查了它:))。
答案 0 :(得分:4)
禁止使用显式接收器调用私有方法。您必须使用隐式接收器(private_bang
,不使用self
)或使用send
。有关详细信息,请参阅my another answer。
顺便说一句,最初的问题是从实例方法调用类实例方法。您的澄清不包括此。但如果仍然如此,则必须使用self.class.send
或将方法设为公共(以便您可以使用显式接收器)。
答案 1 :(得分:1)
让我们考虑一个私有类方法(因为受保护的类方法don't make sense)。
我们知道实例可以自己调用私有方法,只要它不使用显式接收器(self.call_something_private
)。 您似乎也希望实例可以在自己的类上调用私有类方法,但事实并非如此。
让我们看看如何在不使用send
的情况下执行此操作。
private
和protected
宏仅影响当前范围的实例方法,而不影响类方法。以下是重写原始代码的三种方法:
class Bang
def instance_bang
self.class.class_bang
end
# declare method visibility after
def self.class_bang
puts "bang"
end
private_class_method :class_bang
# inline
private_class_method def self.class_bang
puts "bang"
end
# class scope
class << self
# the private macro works here because we're inside the class scope
private
def class_bang
puts "bang"
end
end
end
所以现在我们要在类上公开一个接口来调用class_bang
,但前提是它被Bang
的实例调用。
class Bang
def instance_bang
self.class.invoke_class_bang(self)
end
class << self
private
def class_bang
puts "bang"
end
public
# we ask the receiver to pass itself as an argument ...
def invoke_class_bang(receiver)
# ... so that we can check whether it's
class_bang if receiver.is_a?(Bang)
end
end
end
虽然这不是一个非常漂亮的解决方案。这是一个狡猾的方式:
class Bang
def initialize
def self.instance_bang() self.class.method(:class_bang).call end
end
class << self
private
def class_bang
puts "bang"
end
end
end
答案 2 :(得分:0)
“类方法应该在类范围内使用,因此应该在其中保持可见和可调用,对吧?”是的,这是正确的,这是Ruby展示的行为。 (作为澄清的一点,实例范围不是“在”类范围内。它们恰当地是分开的。)
非send
解决方案是子类化或重新打开类以添加公共类方法来访问受保护的类方法。