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ます。しかし、なぜこれが異なるのですか? selfFoo のインスタンスではありませんpublic_mか? そして、裸のprivate_m電話の受信者は誰ですか? そうではありませんself- 実際に省略したのは、Ruby がそれを行う (自分自身で private_m を呼び出す) からです。

あまり混乱していないことを願っています。私はまだRubyに慣れていません。


編集:すべての回答ありがとうございます。それらをすべてまとめると、私は(ついに)明白なselfことを理解することができました(Rubyのようなものを見たことがない人にとってはそれほど明白ではありません). したがって、プライベート メソッドを呼び出したい場合は、2 つのルールがあります:self暗黙的な受信者でなければならず、その自己は現在のクラスのインスタンスでなければなりません (Exampleその場合、これはインスタンス メソッド定義内にある場合にのみ発生します。メソッドの実行)。間違っている場合は修正してください。

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

Google Trail でこの質問を見つけた人へのメッセージ: これは役に立つかもしれません - http://weblog.jamisbuck.org/2007/2/23/method-visibility-in-ruby

4

7 に答える 7

55

これがそのショートとロングです。Ruby でプライベートが意味するのは、some_instance.private_method(value) などの明示的なレシーバーではメソッドを呼び出すことができないということです。したがって、暗黙的な受信者は自己ですが、例では明示的に自己を使用しているため、プライベートメソッドにはアクセスできません。

このように考えてみてください。クラスのインスタンスに割り当てた変数を使用してプライベート メソッドを呼び出せると思いますか? いいえ。 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=privateselfprivate

于 2010-11-27T21:27:09.827 に答える
14

奇妙ですが、Ruby の可視性修飾子に関する多くの点は奇妙です。が暗黙の受信者であってもself、実際にそれを綴ると、Ruby ランタイムの目には明示的になります。プライベート メソッドを明示的なレシーバーで呼び出すことはできないと言うとき、それは意味することであり、重要selfです。

于 2010-11-27T19:03:22.063 に答える
3

IIRC のプライベート メソッドでは、暗黙的なレシーバーのみが許可されます (もちろん、これは常に self です)。

于 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 に答える
0

質問に正確に答えるわけではありませんが、この方法でプライベートメソッドを呼び出すことができます

class Example
 private
 def example_test
  puts 'Hello'
 end
end

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