为什么这种创建私有类方法的方法有效:
class Person
def self.get_name
persons_name
end
class << self
private
def persons_name
"Sam"
end
end
end
puts "Hey, " + Person.get_name
puts "Hey, " + Person.persons_name #=> raises "private method `persons_name' called for Person:Class (NoMethodError)"
但这不是:
class Person
def self.get_name
persons_name
end
private
def self.persons_name
"Sam"
end
end
puts "Hey, " + Person.get_name
puts "Hey, " + Person.persons_name
答案 0 :(得分:241)
self
), private
似乎不起作用。您可以使用private_class_method
将类方法定义为私有(或者像您描述的那样)。
class Person
def self.get_name
persons_name
end
def self.persons_name
"Sam"
end
private_class_method :persons_name
end
puts "Hey, " + Person.get_name
puts "Hey, " + Person.persons_name
或者(在ruby 2.1+中),由于方法定义返回方法名称的符号,您也可以按如下方式使用它:
class Person
def self.get_name
persons_name
end
private_class_method def self.persons_name
"Sam"
end
end
puts "Hey, " + Person.get_name
puts "Hey, " + Person.persons_name
答案 1 :(得分:101)
ExiRe写道:
红宝石的这种行为真的令人沮丧。我的意思是,如果你搬家 私有部分self.method然后它不是私人的。但如果 你把它移到了班级&lt;&lt;自我然后它突然起作用。 这真是令人作呕。
令人困惑的可能是,令人沮丧的可能是,但令人厌恶的绝对不是。
一旦理解了Ruby的对象模型和相应的method lookup flow,这是非常有意义的,特别是考虑到private
NOT 是一个访问/可见性修饰符,但实际上一个方法调用(以类作为其接收者),正如所讨论的here ...在Ruby中没有“私有部分”这样的东西。
要定义私有实例方法,可以在实例的类上调用private
,将随后定义的方法的默认可见性设置为私有...因此定义私有方法非常有意义通过在类的类上调用private
来获取类方法,即。它的元类。
其他主流的,自称为OO的语言可能会给你一个不那么混乱的语法,但是如果没有Ruby的元编程功能,你绝对可以将它与一个令人困惑且不太一致的(不一致?)对象模型进行交换。设施。
答案 2 :(得分:63)
默认情况下,所有类方法都是公共的。要将它们设为私有,您可以像@tjwallace一样使用Module#private_class_method编写或以不同的方式定义它们,如下所示:
class << self
private
def method_name
...
end
end
class << self
打开self的单例类,以便可以为当前的自身对象重新定义方法。这用于定义类/模块(“静态”)方法。只有在那里,定义私有方法才能真正为您提供私有类方法。
答案 3 :(得分:11)
为了完整性,我们还可以避免在单独的行中声明private_class_method。我个人不喜欢这种用法,但很高兴知道它存在。
private_class_method def self.method_name
....
end
答案 4 :(得分:4)
我也是,发现Ruby(或者至少我对它的了解)没有达标 在这方面。例如,以下是我想要的,但是很笨,
class Frob
attr_reader :val1, :val2
Tolerance = 2 * Float::EPSILON
def initialize(val1, val2)
@val2 = val1
@val2 = val2
...
end
# Stuff that's likely to change and I don't want part
# of a public API. Furthermore, the method is operating
# solely upon 'reference' and 'under_test' and will be flagged as having
# low cohesion by quality metrics unless made a class method.
def self.compare(reference, under_test)
# special floating point comparison
(reference - under_test).abs <= Tolerance
end
private_class_method :compare
def ==(arg)
self.class.send(:compare, val1, arg.val1) &&
self.class.send(:compare, val2, arg.val2) &&
...
end
end
我上面代码的问题是Ruby语法要求 而且我的代码质量指标也适用于繁琐的代码。 为了使代码既可以按照我想要的方式工作,也可以安静指标,我必须这样做 使compare()成为一个类方法。因为我不希望它成为其中的一部分 这个类的公共API,我需要它是私有的,但是'私有' 本身不起作用。相反,我强迫使用'private_class_method' 或者一些这样的解决方法。反过来,这迫使使用 'self.class.send(:compare ...'为我在'==()'中测试的每个变量。 现在这有点笨拙。
答案 5 :(得分:3)
实例方法在类定义块中定义。类方法在类的单例类上定义为单例方法,也非正式地称为“元类”或“特征类”。 private
不是关键字,而是方法(Module#private)。
这是对方法self#private
/ A#private
的调用,它会为所有即将发生的实例方法定义“切换”私有访问,直到切换为其他方式:
class A
private
def instance_method_1; end
def instance_method_2; end
# .. and so forth
end
如前所述,类方法实际上是在单例类上定义的单例方法。
def A.class_method; end
或者使用特殊语法打开匿名单例类A:
的定义主体class << A
def class_method; end
end
“消息私有”的接收者 - self - 在class A
内是类对象A. class << A
块内的self是另一个对象,单例类。
以下示例实际上调用了两种不同的方法,称为 private ,使用两个不同的收件人或目标进行调用。在第一部分中,我们定义了一个私有实例方法(“在类A上”),在后者中我们定义了一个私有类方法(实际上是A的单例类对象上的单例方法)。
class A
# self is A and private call "A.private()"
private def instance_method; end
class << self
# self is A's singleton class and private call "A.singleton_class.private()"
private def class_method; end
end
end
现在,重写一下这个例子:
class A
private
def self.class_method; end
end
你能看到[Ruby语言设计师]犯下的错误吗?您为A的所有即将发生的实例方法切换私有访问,但继续在不同的类(单例类)上声明单例方法。
答案 6 :(得分:-1)
Ruby似乎提供了一个糟糕的解决方案。为了说明,从一个简单的开始 显示访问私有类方法的C ++示例:
#include <iostream>
class C
{
public:
void instance_method(void)
{
std::cout << "instance method\n";
class_method(); // !!! LOOK !!! no 'send' required. We can access it
// because 'private' allows access within the class
}
private:
void static class_method(void) { std::cout << "class method\n"; }
};
int main()
{
C c;
c.instance_method(); // works
// C::class_method() does not compile - it's properly private
return 0;
}
运行以上
% ./a.out
instance method
class method
现在Ruby似乎没有提供相应的功能。我认为Ruby的规则是 私有方法一定不能被接收者访问。也就是说,
inst.pvt_method # FAILS
pvt_method # WORKS only within the class (good)
对于私有实例方法可以,但是会导致私有类出现问题 方法。
我希望Ruby这样运行:
class C
def instance_method
STDOUT << "instance method\n"
# Simple access to the private class method would be nice:
class_method # DOES NOT WORK. RUBY WON'T FIND THE METHOD
C.class_method # DOES NOT WORK. RUBY WON'T ALLOW IT
# ONLY THIS WORKS. While I am happy such capability exists I think
# the way 'send' should be used is when the coder knows he/she is
# doing a no-no. The semantic load on the coder for this is also
# remarkably clumsy for an elegant language like ruby.
self.class.send(:class_method)
end
private_class_method def self.class_method() STDOUT << "class method\n"; end
end
但是,a,上述方法不起作用。有人知道更好的方法吗?
当我在方法之前看到“发送”时,这是代码明显违反的明确标志 API设计者的意图,但是在这种情况下,设计是专门 让该类的实例方法调用私有类方法。
答案 7 :(得分:-11)
至于红宝石2.3.0
class Check
def self.first_method
second_method
end
private
def self.second_method
puts "well I executed"
end
end
Check.first_method
#=> well I executed