如何创建私有类方法?

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的元编程功能,你绝对可以将它与一个令人困惑且不太一致(不一致?)的对象模型进行交换.

  • @Edward这是_designed_那样的方式http://junichiito.blogspot.co.uk/2012/03/matz-answers-why-ruby-lets-sub-classes.html.为什么"适当"? (13认同)

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)


Mar*_*son 6

实例方法在类定义块中定义。类方法被定义为类的单例类上的单例方法,也非正式地称为“元类”或“特征类”。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 的所有即将到来的实例方法打开私有访问,但继续在不同的类(单例类)上声明单例方法。


din*_*022 5

我也是,在这方面,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 ...'),这有点笨拙。