有没有办法从 Ruby 中的实例调用私有类方法?

发布于 2024-07-05 06:06:40 字数 454 浏览 12 评论 0原文

当然,除了 self.class.send :method, args... 。 我想在类和实例级别提供一个相当复杂的方法,而无需重复代码。


更新:

@Jonathan Branam:这是我的假设,但我想确保没有其他人找到解决方法。 Ruby 中的可见性与 Java 中的可见性有很大不同。 您也说得对, private 不适用于类方法,尽管这将声明一个私有类方法:

class Foo
  class <<self
    private
    def bar
      puts 'bar'
    end
  end
end

Foo.bar
# => NoMethodError: private method 'bar' called for Foo:Class

Other than self.class.send :method, args..., of course. I'd like to make a rather complex method available at both the class and instance level without duplicating the code.


UPDATE:

@Jonathan Branam: that was my assumption, but I wanted to make sure nobody else had found a way around. Visibility in Ruby is very different from that in Java. You're also quite right that private doesn't work on class methods, though this will declare a private class method:

class Foo
  class <<self
    private
    def bar
      puts 'bar'
    end
  end
end

Foo.bar
# => NoMethodError: private method 'bar' called for Foo:Class

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

安静 2024-07-12 06:06:40

这是与问题相关的代码片段。 在类定义中使用“private”不适用于类方法。 您需要使用“private_class_method”,如下例所示。

class Foo
  def self.private_bar
    # Complex logic goes here
    puts "hi"
  end
  private_class_method :private_bar
  class <<self
    private
    def another_private_bar
      puts "bar"
    end
  end
  public
  def instance_bar
    self.class.private_bar
  end
  def instance_bar2
    self.class.another_private_bar
  end
end

f=Foo.new
f=instance_bar # NoMethodError: private method `private_bar' called for Foo:Class
f=instance_bar2 # NoMethodError: private method `another_private_bar' called for Foo:Class

我看不出有什么办法可以解决这个问题。 文档说你不能指定私有方法的接收。 此外,您只能从同一实例访问私有方法。 类 Foo 是一个与给定的 Foo 实例不同的对象。

不要将我的答案视为最终答案。 我当然不是专家,但我想提供一个代码片段,以便其他尝试回答的人将拥有正确的私有类方法。

Here is a code snippet to go along with the question. Using "private" in a class definition does not apply to class methods. You need to use "private_class_method" as in the following example.

class Foo
  def self.private_bar
    # Complex logic goes here
    puts "hi"
  end
  private_class_method :private_bar
  class <<self
    private
    def another_private_bar
      puts "bar"
    end
  end
  public
  def instance_bar
    self.class.private_bar
  end
  def instance_bar2
    self.class.another_private_bar
  end
end

f=Foo.new
f=instance_bar # NoMethodError: private method `private_bar' called for Foo:Class
f=instance_bar2 # NoMethodError: private method `another_private_bar' called for Foo:Class

I don't see a way to get around this. The documentation says that you cannot specify the receive of a private method. Also you can only access a private method from the same instance. The class Foo is a different object than a given instance of Foo.

Don't take my answer as final. I'm certainly not an expert, but I wanted to provide a code snippet so that others who attempt to answer will have properly private class methods.

手心的海 2024-07-12 06:06:40

让我为这个或多或少奇怪的解决方案和非解决方案列表做出贡献:

puts RUBY_VERSION # => 2.1.2

class C
  class << self
    private def foo
      'Je suis foo'
    end
  end

  private define_method :foo, &method(:foo)

  def bar
    foo
  end
end

puts C.new.bar # => Je suis foo
puts C.new.foo # => NoMethodError

Let me contribute to this list of more or less strange solutions and non-solutions:

puts RUBY_VERSION # => 2.1.2

class C
  class << self
    private def foo
      'Je suis foo'
    end
  end

  private define_method :foo, &method(:foo)

  def bar
    foo
  end
end

puts C.new.bar # => Je suis foo
puts C.new.foo # => NoMethodError
jJeQQOZ5 2024-07-12 06:06:40

现在你不再需要辅助方法了。 您可以简单地将它们内联到您的方法定义中。 对于 Java 人员来说,这应该非常熟悉:

class MyClass

  private_class_method def self.my_private_method
    puts "private class method"
  end

  private def my_private_method
    puts "private instance method"
  end

end

不,您不能从实例方法调用私有类方法。 但是,您可以使用 private_constant< 将 private 类方法实现为 private 嵌套类中的 public 类方法。 /code> 辅助方法。 有关更多详细信息,请参阅此博文

Nowadays you don't need the helper methods anymore. You can simply inline them with your method definition. This should feel very familiar to the Java folks:

class MyClass

  private_class_method def self.my_private_method
    puts "private class method"
  end

  private def my_private_method
    puts "private instance method"
  end

end

And no, you cannot call a private class method from an instance method. However, you could instead implement the the private class method as public class method in a private nested class instead, using the private_constant helper method. See this blogpost for more detail.

掩饰不了的爱 2024-07-12 06:06:40

如果您的方法仅仅是一个实用函数(也就是说,它不依赖在任何实例变量上),您可以将该方法放入模块中,并包含扩展该类,以便它既可用作私有类方法又可用作私有实例方法。

If your method is merely a utility function (that is, it doesn't rely on any instance variables), you could put the method into a module and include and extend the class so that it's available as both a private class method and a private instance method.

把昨日还给我 2024-07-12 06:06:40

这是使用“真正的”私有类方法的方法。

class Foo
  def self.private_bar
    # Complex logic goes here
    puts "hi"
  end
  private_class_method :private_bar
  class <<self
    private
    def another_private_bar
      puts "bar"
    end
  end
  public
  def instance_bar
    self.class.private_bar
  end
  def instance_bar2
    self.class.another_private_bar
  end
  def calling_private_method
    Foo.send :another_private_bar
    self.class.send :private_bar
  end
end
f=Foo.new
f.send :calling_private_method 
 # "bar"
 # "hi"
Foo.send :another_private_bar
# "bar"

干杯

This is the way to play with "real" private class methods.

class Foo
  def self.private_bar
    # Complex logic goes here
    puts "hi"
  end
  private_class_method :private_bar
  class <<self
    private
    def another_private_bar
      puts "bar"
    end
  end
  public
  def instance_bar
    self.class.private_bar
  end
  def instance_bar2
    self.class.another_private_bar
  end
  def calling_private_method
    Foo.send :another_private_bar
    self.class.send :private_bar
  end
end
f=Foo.new
f.send :calling_private_method 
 # "bar"
 # "hi"
Foo.send :another_private_bar
# "bar"

cheers

假装不在乎 2024-07-12 06:06:40

这可能是最“原生的 Ruby”方式:

class Foo
  module PrivateStatic # like Java
    private def foo
      'foo'
    end
  end
  extend PrivateStatic
  include PrivateStatic

  def self.static_public_call
    "static public #{foo}"
  end

  def public_call
    "instance public #{foo}"
  end
end

Foo.static_public_call # 'static public foo'
Foo.new.public_call # 'instance public foo'
Foo.foo # NoMethodError: private method `foo' called for Foo:Class
Foo.new.foo # NoMethodError: private method `foo' called for #<Foo:0x00007fa154d13f10>

通过一些 Ruby 元编程,您甚至可以使其看起来像:

class Foo
  def self.foo
    'foo'
  end

  extend PrivateStatic
  private_static :foo
end

Ruby 的元编程非常强大,因此您可以在技术上实现您可能想要的任何范围规则。 话虽这么说,我仍然更喜欢第一个变体的清晰度和最小的惊喜

This is probably the most "native vanilla Ruby" way:

class Foo
  module PrivateStatic # like Java
    private def foo
      'foo'
    end
  end
  extend PrivateStatic
  include PrivateStatic

  def self.static_public_call
    "static public #{foo}"
  end

  def public_call
    "instance public #{foo}"
  end
end

Foo.static_public_call # 'static public foo'
Foo.new.public_call # 'instance public foo'
Foo.foo # NoMethodError: private method `foo' called for Foo:Class
Foo.new.foo # NoMethodError: private method `foo' called for #<Foo:0x00007fa154d13f10>

With some Ruby metaprogramming, you could even make it look like:

class Foo
  def self.foo
    'foo'
  end

  extend PrivateStatic
  private_static :foo
end

Ruby's metaprogramming is quite powerful, so you could technically implement any scoping rules you might want. That being said, I'd still prefer the clarity and minimal surprise of the first variant.

最终幸福 2024-07-12 06:06:40

前面的例子(不再?)有效。 不能直接调用私有类方法; 即使来自同一个班级。 相反,您需要使用send

class Foo
  def self.a_method
    puts "uses #{private_method} from class method"
  end

  def a_method
    # normally this would be done with an alias or include+extend a module or calling self.class.a_method
    puts "uses #{private_method} from instance method"
  end

  class << self
    private

    def private_method
      "private class method"
    end
  end

  private

  def private_method
    self.class.send(:private_method)
  end
end

Foo.a_method => 'uses private class method from class method'
Foo.new.a_method => 'uses private class method from instance method'

The prior examples (no longer?) work. You cannot call the private class method directly; even from within the same class. Instead, you need to use send.

class Foo
  def self.a_method
    puts "uses #{private_method} from class method"
  end

  def a_method
    # normally this would be done with an alias or include+extend a module or calling self.class.a_method
    puts "uses #{private_method} from instance method"
  end

  class << self
    private

    def private_method
      "private class method"
    end
  end

  private

  def private_method
    self.class.send(:private_method)
  end
end

Foo.a_method => 'uses private class method from class method'
Foo.new.a_method => 'uses private class method from instance method'
萝莉病 2024-07-12 06:06:40

除非我误解了,否则您不需要这样的东西:

class Foo
    private
    def Foo.bar
        # Complex logic goes here
        puts "hi"
    end

    public
    def bar
        Foo.bar
    end
end

当然,如果您想避免对类名进行硬编码,您可以更改第二个定义以使用 self.class.send 方法...

Unless I'm misunderstanding, don't you just need something like this:

class Foo
    private
    def Foo.bar
        # Complex logic goes here
        puts "hi"
    end

    public
    def bar
        Foo.bar
    end
end

Of course you could change the second definition to use your self.class.send approach if you wanted to avoid hardcoding the class name...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文