99m*_*les 213 ruby access-specifier
为什么这种创建私有类方法的方法有效:
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)"
Run Code Online (Sandbox Code Playgroud)
但这不是:
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
Run Code Online (Sandbox Code Playgroud)
tjw*_*ace 260
private如果您在显式对象上定义方法(在您的情况下self)似乎不起作用.您可以使用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
Run Code Online (Sandbox Code Playgroud)
或者(在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
Run Code Online (Sandbox Code Playgroud)
pva*_*erk 104
ExiRe写道:
红宝石的这种行为真的令人沮丧.我的意思是,如果你移动私人部分self.method然后它不是私人的.但是如果你把它移到"自我"这一类,那它就会突然发挥作用.这真是令人作呕.
令人困惑的可能是,令人沮丧的可能是,但令人作呕的绝对不是.
这非常有意义,一旦你了解Ruby的对象模型和相应的方法查找流程,特别是考虑到时private是不是访问/可见性修饰符,但实际上一个方法调用(与类作为其接收方)为讨论在这里 ... 在Ruby中没有"私有部分"这样的东西.
要定义私有实例方法,可以调用private实例的类来将随后定义的方法的默认可见性设置为private ...因此,通过调用类的类来定义私有类方法是完全合理private的,即.它的元类.
其他主流的,自称为OO的语言可能会给你一个不那么混乱的语法,但是如果没有Ruby的元编程功能,你绝对可以将它与一个令人困惑且不太一致(不一致?)的对象模型进行交换.
rox*_*xxy 71
默认情况下,所有类方法都是公共的 要将它们设为私有,您可以像@tjwallace一样使用Module#private_class_method编写或以不同方式定义它们,就像您一样:
class << self
private
def method_name
...
end
end
Run Code Online (Sandbox Code Playgroud)
class << self打开self的singleton类,以便可以为当前的self对象重新定义方法.这用于定义类/模块("静态")方法.只有那里,定义私有方法真的给你私有类方法.
小智 15
只是为了完整性,我们还可以避免在单独的行中声明private_class_method.我个人不喜欢这种用法,但很高兴知道它存在.
private_class_method def self.method_name
....
end
Run Code Online (Sandbox Code Playgroud)
实例方法在类定义块中定义。类方法被定义为类的单例类上的单例方法,也非正式地称为“元类”或“特征类”。private不是关键字,而是方法(Module#private)。
这是对方法self#private/的调用,A#private它“切换”所有即将到来的实例方法定义的私有访问,直到以其他方式切换:
class A
private
def instance_method_1; end
def instance_method_2; end
# .. and so forth
end
Run Code Online (Sandbox Code Playgroud)
如前所述,类方法实际上是在单例类上定义的单例方法。
def A.class_method; end
Run Code Online (Sandbox Code Playgroud)
或者使用特殊语法打开 A 的匿名单例类的定义体:
class << A
def class_method; end
end
Run Code Online (Sandbox Code Playgroud)
“消息私有”的接收者——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
Run Code Online (Sandbox Code Playgroud)
现在,稍微重写一下这个例子:
class A
private
def self.class_method; end
end
Run Code Online (Sandbox Code Playgroud)
你能看到 [Ruby 语言设计者] 所犯的错误吗?您为 A 的所有即将到来的实例方法打开私有访问,但继续在不同的类(单例类)上声明单例方法。
我也是,在这方面,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
Run Code Online (Sandbox Code Playgroud)
我上面的代码的问题是Ruby语法要求和我的代码质量指标共同构成了繁琐的代码。为了使代码都能按我希望的方式工作并且使指标安静,我必须使compare()为类方法。由于我不希望它成为该类的公共API的一部分,因此我需要将其设为私有,但是“私有”本身不起作用。相反,我被迫使用'private_class_method'或类似的解决方法。反过来,这会强制我在'==()'中测试的每个变量都使用'self.class.send(:compare ...'),这有点笨拙。