如何创建一个私有类方法?

这种创建私有类方法是如何工作的:

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
118351 次浏览

如果你在显式对象上定义一个方法(在你的例子中是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

默认情况下,所有类方法都是公共的。要使它们私有,你可以像@tjwallace那样使用模块# private_class_method,或者像你所做的那样以不同的方式定义它们:

class << self


private


def method_name
...
end
end

class << self打开了self的单例类,这样就可以为当前self对象重新定义方法。这是用来定义类/模块(“静态”)方法。只有在这里,定义私有方法才能真正提供私有类方法。

ExiRe写道:

ruby的这种行为真是令人沮丧。我的意思是如果你移动 以私室自居。方法,那么它不是私有的。但是,如果 你把它移到班级<<然后它突然起作用了。

它可能令人困惑,可能令人沮丧,但绝对不会令人恶心。

一旦你理解了Ruby的对象模型和相应的方法查找流,这就完全有意义了,尤其是考虑到private是一个访问/可见性修饰符,但实际上是一个方法调用(以类作为接收者),如前面讨论的在这里…在Ruby中没有“私人区域”这样的东西。

要定义私有的实例方法,在实例的类上调用private来将随后定义的方法的默认可见性设置为私有…因此,通过在类的类上调用private来定义私有方法是非常有意义的。它的元类。

其他主流的,自称的OO语言可能会给你一个不那么令人困惑的语法,但你肯定会在没有Ruby元编程功能的情况下,用一个令人困惑且不太一致的(不一致?)对象模型来交换。

我也发现Ruby(或者至少我对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(:比较…'为我在'==()'中测试的每个变量。 这有点麻烦。

为了完整起见,我们还可以避免在单独的行中声明private_class_method。我个人不喜欢这种用法,但很高兴知道它的存在。

private_class_method  def self.method_name
....
end

实例方法在类定义块中定义。类方法定义为类的单例类上的单例方法,也非正式地称为“元类”或“特征类”。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

class A中的“message private”- 自我 -的接收者是类对象a。class << A块中的self是另一个对象,即单例类。

下面的例子实际上调用了两个不同的方法私人,使用了两个不同的接收者或目标进行调用。在第一部分中,我们定义了一个私有实例方法(“在类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的所有即将出现的实例方法切换私有访问,但继续在另一个类上声明单例方法,即单例类。

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的规则是这样的 接收方不能访问私有方法。也就是说,< / p >
inst.pvt_method  # FAILS
pvt_method # WORKS only within the class (good)

这对于私有实例方法是可以的,但是对于私有类会产生问题 方法。< / p >

我希望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

但是,遗憾的是,上述方法并不奏效。有人知道更好的办法吗?

当我看到'发送'之前的方法,这是一个明显的迹象,代码违反 API的设计者的意图,但在这种情况下,设计是特别的 要使类的实例方法调用私有类方法