3

Rubyはクラスとオブジェクトに関してかなり一貫しています。ただし、トップレベルのメソッド宣言に関しては、そのルールはどういうわけか壊れています。例えば、

$ puts self # => main
$ puts self.class # => Object

ただし、このmainオブジェクトのコンテキストで宣言されたメソッドは、クラスのプライベートメソッドとして何らかの形で利用できますObject

これについて論理的な説明はありますか?これらのメソッドは「スタンドアロン関数」として表示されるため、これは非常に便利ですが、「それだけ」と同じように解釈すると、通常はクラスのコンテキストでメソッドを定義する必要があるため、他の点では一貫性のあるルールに違反します。それがそのクラスのメソッドであるために。ただし、mainオブジェクトはクラスではなくObject、クラスでもありません。

私の質問を再構成する: メソッドはどのスコープでrubyのREPL内で宣言されますか?{クラスオブジェクト/オブジェクトメインまたはモジュールカーネル}

REPLで宣言されたメソッドのプライベートな性質については、plzは次の例を参照してください。

def my_method # "a method declared in REPL"
  puts "method called"
end

# calling my_method in REPL aka top-level scope
my_method # => "method called"
[].my_method # => private method `my_method' called for []:Array (NoMethodError)
Array.my_method # => private method `my_method' called for Array:Class (NoMethodError)

Q:my_methodがクラスObjectの下のプライベートメソッドとして定義されている場合、なぜクラスObjectではなくmainに自己設定されるのですか。誰かがそれがプライベートスコープの下にないと言った場合、なぜ私は上記のエラーが発生するのですか?

4

3 に答える 3

3

質問を完全に理解できるかどうかはわかりませんが、次のように答えようとします。

あなたが内部で働いているとき、irbあなたは本当にこのような文脈で働いています:

class Object
  # you're here
end

したがって、REPL内でメソッドを宣言すると、実際にはmainのクラス内でメソッドを宣言していることになります。

ruby-1.9.3-rc1 :001 > def foo; end
 => nil 
ruby-1.9.3-rc1 :002 > self.class.public_methods.include?(:foo)
 => true 

そこで定義されているメソッドがクラス専用であるという考えがどこで得られるかはわかりません(ただし、質問を誤解している可能性があります)。

内部にあるクラスにはモジュールがirb含まれているKernelため、その関数にアクセスできます(クラス内にいるため、通常のメソッドであるにもかかわらず、スタンドアロン関数として表示されます)。

ruby-1.9.3-rc1 :003 > self.class.included_modules
 => [Kernel] 

これにより、通常のRubyの動作と一致し、実際、Objectクラス内にありますmainself

電話をかけると、検査を通じてそれを行うように指示されているので、self受け取ることができます。からメソッドmainを削除して、実際の値を確認できます。#to_sself

ruby-1.9.3-p0 :001 > self
 => main 
ruby-1.9.3-p0 :002 > class << self; remove_method :to_s; end
 => #<Class:#<Object:0x007fc08387af00>> 
ruby-1.9.3-p0 :003 > self
 => #<Object:0x007fc08387af00 @prompt={:PROMPT_I=>"ruby-1.9.3-p0 :%03n > ", :PROMPT_S=>"ruby-1.9.3-p0 :%03n%l> ", :PROMPT_C=>"ruby-1.9.3-p0 :%03n > ", :PROMPT_N=>"ruby-1.9.3-p0 :%03n?> ", :RETURN=>" => %s \n", :AUTO_INDENT=>true}> 

編集:先に進む前に、使用しているRubyのバージョンを明確にする必要があると思います。1.9.3については以下のサンプルを参照してください。

ruby-1.9.3-p0 :001 > def my_method
ruby-1.9.3-p0 :002?>     puts "method called"
ruby-1.9.3-p0 :003?> end
 => nil 
ruby-1.9.3-p0 :004 > 
ruby-1.9.3-p0 :005 >   [].my_method
method called
 => nil 
ruby-1.9.3-p0 :006 > Array.my_method 
method called
于 2012-07-13T17:15:17.630 に答える
2

IMOの最上位メソッドは、クラスではなくモジュールのコンテキストでKernel定義されるため、インスタンスメソッドとクラスメソッドObjectの両方になります(クラスにも含まれるため)。ObjectClassKernel

def a_method
  "inside a_method"
end

public :a_method

p Object.a_method
p Object.new.a_method
p self.a_method
p Kernel.a_method

これにより、どのような状況でも使用できます。

更新:それはさらに単純で、Module.superclassですObject。そのため、何かを定義すると、インスタンスメソッドObjectとしても終了します。Moduleそして、Class.superclassはであるModuleため、すべてのクラスのクラスメソッドとしても使用されます。また、Kernel.classはであるためModuleKernel.a_methodはクラスのインスタンスメソッドですModule。まあ、本当に簡単ですか?

于 2012-07-13T19:39:08.680 に答える
0

クラス内にいないときにトップレベルでメソッド/関数を定義できる理由を尋ねる場合、答えは、それが属するクラスのオブジェクトでメソッドを定義することもできるということです。例を見てみましょう。

class C
  def f
    def g
      'g'
    end
    'f'
  end
end

C.new.g # NoMethodError: undefined method `g' for #<C:0x0>
C.new.f # => 'f'
C.new.g # => 'g'

これを行うことはお勧めしませんが、この場合は一貫しています。

于 2012-07-13T20:31:54.397 に答える