web-dev-qa-db-ja.com

Rubyのプライベートメソッドを理解する

class Example
 private
 def example_test
  puts 'Hello'
 end
end

e = Example.new
e.example_test

もちろん、これは機能しません。なぜなら、明示的な受信者-例のインスタンス(e)を指定したからです。これは「プライベートルール」に反します。

しかし、なぜRuby this:

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_mprivate_mに変更する必要があります。しかし、なぜこれが異なるのか、selfpublic_m内のFooのインスタンスではありませんか?ベアワードprivate_m呼び出しの受信者は誰ですか?それはselfではありません-実際に何を省略しているのですか、Rubyはあなたのためにそれを行います(自分でprivate_mを呼び出す)?

混乱させすぎないように願っています。Rubyにはまだ新鮮です。


編集:すべての答えをありがとう。それらをすべてまとめると、(最終的に)明白な(そしてRubyのようなものを見たことがない人にとってはそれほど明白ではない)を理解することができました:self自体が明示的および暗黙的なレシーバーであり、それが違いを生むことができます。したがって、プライベートメソッドを呼び出す場合は、2つのルールがあります: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

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

49
Ernest

ここに短いものと長いものがあります。 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
51
Mike Bethany

definition of private in Rubyは、「明示的な受信者なしでのみ呼び出すことができます」。それが、他の説明はありません。

実際にはルールには例外があることに注意してください。ローカル変数とメソッド呼び出しのあいまいさのため、以下はalwaysがローカル変数への割り当てとして解決されます。

foo = :bar

foo=というライターを呼び出す場合はどうしますか?さて、あなたはhave明示的なレシーバーを追加します、なぜならレシーバーなしではRubyは単にメソッドfoo=を呼び出す代わりにローカル変数fooに割り当てる:

self.foo = :bar

しかし、foo=というprivateライターを呼び出したい場合はどうしますか? できないself.foo =foo=privateであり、したがって明示的なレシーバーで呼び出すことができないため、書き込みます。さて、実際にはthis特定のケース(およびこのケースalone)の場合、canは実際にselfの明示的なレシーバーを使用してprivateライターを呼び出します。

17
Jörg W Mittag

奇妙ですが、Rubyの可視性修飾子に関する多くのことは奇妙です。 selfが暗黙のレシーバーであっても、実際にスペルアウトすると、Rubyランタイム。目に見えて明示的になります。 、それはselfカウントでも意味します。

14
Theo

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

3
Victor Deryagin

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
1
Dinesh Pallapa

私のprevoiusの回答でごめんなさい。あなたの質問がわかりません。

コードを次のように変更しました。

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
1
demas

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

class Example
 private
 def example_test
  puts 'Hello'
 end
end

e = Example.new
e.send(:example_test)
0
gates