52
class Example
 private
 def example_test
  puts 'Hello'
 end
end

e = Example.new
e.example_test

这当然行不通,因为我们指定了明确的接收者——Example ( e) 的实例,这违反了“私人规则”。

但我无法理解,为什么不能在 Ruby 中这样做:

class Foo
 def public_m
  self.private_m # <=
 end
 private
 def private_m
  puts 'Hello'
 end
end

Foo.new.public_m

方法定义中的当前对象public_m(即self)是 Foo 的实例。那么为什么不允许呢?要解决这个问题,我必须更改self.private_m为 just private_m。但是为什么会有所不同,self里面不是 Foo 的一个实例public_m吗?谁是空话private_m呼叫的接收者?不是self吗 - 实际上你省略了什么,因为 Ruby 会为你做这件事(会在 self 上调用 private_m)?

我希望我没有把它混淆太多,我对 Ruby 还是很陌生。


编辑:谢谢你的所有答案。将它们放在一起,我能够(最终)理解显而易见的(对于从未见过像 Ruby 这样的东西的人来说并不那么明显):它self本身可以是显式和隐式接收器,并且会有所作为。因此,如果要调用私有方法,有两条规则:self必须是隐式接收者,并且 self 必须是当前类的实例(Example在这种情况下 - 并且仅当 self 如果在实例方法定义中,在此期间发生方法执行)。如果我错了,请纠正我。

class Example 

 # self as an explicit receiver (will throw an error)
 def explicit 
  self.some_private_method
 end

 # self as an implicit receiver (will be ok)
 def implicit
  some_private_method
 end

 private

 def some_private_method; end
end

Example.new.implicit

给在谷歌追踪期间可以找到这个问题的任何人的消息:这可能会有所帮助 - http://weblog.jamisbuck.org/2007/2/23/method-visibility-in-ruby

4

7 回答 7

55

这是它的短和长。Ruby 中私有的意思是不能用显式接收者调用方法,例如 some_instance.private_method(value)。因此,即使隐式接收器是 self,但在您的示例中,您明确使用 self,因此无法访问私有方法。

这样想,您是否希望能够使用分配给类实例的变量来调用私有方法?不,Self 是一个变量,因此它必须遵循相同的规则。但是,当您只是在实例中调用该方法时,它会按预期工作,因为您没有明确声明接收者。

Ruby 就是你实际上可以使用 instance_eval 调用私有方法:

class Foo
  private
  def bar(value)
    puts "value = #{value}"
  end
end

f = Foo.new
begin
  f.bar("This won't work")
rescue Exception=>e
  puts "That didn't work: #{e}"
end
f.instance_eval{ bar("But this does") }

希望这更清楚一点。

- 编辑 -

我假设你知道这会起作用:

class Foo
 def public_m
  private_m # Removed self.
 end
 private
 def private_m
  puts 'Hello'
 end
end

Foo.new.public_m
于 2010-11-27T19:01:01.940 回答
17

Ruby 中的定义private“只能在没有显式接收者的情况下调用”。这就是为什么你只能在没有明确接收者的情况下调用私有方法。没有其他解释。

请注意,该规则实际上有一个例外:由于局部变量和方法调用之间的歧义,以下将始终被解析为对局部变量的赋值:

foo = :bar

那么,如果你想打电话给一个叫做 的作家,你会怎么做foo=?好吧,您必须添加一个显式接收器,因为没有接收器 Ruby 根本不会知道您要调用该方法foo=而不是分配给局部变量foo

self.foo = :bar

但是如果你想打电话给一个private作家,你会怎么做foo=?你不能self.foo =,因为foo=isprivate并且因此不能用显式接收器调用。好吧,实际上对于这种特定情况(以及这种情况),您实际上可以使用显式接收器self来调用编写器private

于 2010-11-27T21:27:09.827 回答
14

这很奇怪,但是关于 Ruby 的可见性修饰符的许多事情都很奇怪。即使self是隐式接收器,在 Ruby 运行时的眼中,实际上将其拼写出来也会使其显式。当它说私有方法不能用显式接收器调用时,这就是它的意思,甚至很self重要。

于 2010-11-27T19:03:22.063 回答
3

IIRC,私有方法允许隐式接收器(当然,它总是自我)。

于 2010-11-27T18:46:35.693 回答
1

对不起我以前的回答。我只是不明白你的问题。

我像这样更改了您的代码:

class Foo
 def public_m
  private_m # <=
 end

 def Foo.static_m
   puts "static"
 end

 def self.static2_m
   puts "static 2"
 end

 private 
 def private_m
  puts 'Hello'
 end
end

Foo.new.public_m
Foo.static_m
Foo.static2_m

这是实例方法的调用:

 def public_m
  private_m # <=
 end

下面是类方法的调用:

 def Foo.static_m
   puts "static"
 end

 def self.static2_m
   puts "static 2"
 end

Foo.static_m
Foo.static2_m
于 2010-11-27T19:10:58.667 回答
1

为 User Gates 解决方案添加一些增强功能。将私有方法调用到类方法或实例方法几乎是可能的。这是代码片段。但不推荐。

类方法

class Example
  def public_m
    Example.new.send(:private_m)
  end

  private
  def private_m
    puts 'Hello'
  end
end

e = Example.new.public_m

实例方法

class Example
  def self.public_m
    Example.new.send(:private_m)
  end

  private
  def private_m
    puts 'Hello'
  end
end

e = Example.public_m
于 2018-02-09T09:20:41.267 回答
0

不完全回答问题,但您可以通过这种方式调用私有方法

class Example
 private
 def example_test
  puts 'Hello'
 end
end

e = Example.new
e.send(:example_test)
于 2017-02-27T12:47:53.433 回答