メソッド内にメソッドを含めることは可能ですか?


89

メソッドの中にメソッドがあります。内点法は、実行されている変数ループに依存します。それは悪い考えですか?


2
コードサンプル、または少なくともあなたがやろうとしていることと論理的に同等のものを共有できますか?
アーロンスクラッグス2011

回答:


165

更新:この回答は最近関心を集めているようですので、ここで説明した機能削除する、つまりメソッド本体内にメソッド定義を含めることを禁止するためのRuby課題追跡システムに関する議論があることを指摘したいと思います。


いいえ、Rubyにはネストされたメソッドがありません。

あなたはこのようなことをすることができます:

class Test1
  def meth1
    def meth2
      puts "Yay"
    end
    meth2
  end
end

Test1.new.meth1

しかし、それはネストされたメソッドではありません。繰り返しますが、Rubyにネストされたメソッドがありません

これは、動的なメソッド定義です。を実行するとmeth1、の本体meth1が実行されます。本体はたまたまという名前のメソッドを定義しmeth2ているため、meth1一度実行した後、を呼び出すことができます。meth2

しかし、どこでmeth2定義されていますか?Rubyにネストされたメソッドがないため、ネストされたメソッドとして定義されていないことは明らかです。これは、次のインスタンスメソッドとして定義されています。Test1

Test1.new.meth2
# Yay

また、実行するたびに明らかに再定義されますmeth1

Test1.new.meth1
# Yay

Test1.new.meth1
# test1.rb:3: warning: method redefined; discarding old meth2
# test1.rb:3: warning: previous definition of meth2 was here
# Yay

つまり、いいえ、Rubyネストされたメソッドをサポートしていません

Rubyでは、メソッド本体をクロージャにすることはできず、ブロック本体のみをクロージャにすることができることにも注意してください。Rubyがネストされたメソッドをサポートしていてもネストされたメソッドで外部メソッドの変数を使用できないため、これにより、ネストされたメソッドの主なユースケースがほとんどなくなります。


更新の続き:後の段階で、この構文はネストされたメソッドをRubyに追加するために再利用される可能性があります。これは、私が説明したように動作します。それらは、包含メソッドにスコープされます。つまり、包含メソッドの外部では非表示でアクセスできません。体。そしておそらく、彼らはそれらを含むメソッドの字句スコープにアクセスできるでしょう。ただし、上記でリンクした説明を読むと、matzがネストされたメソッドに大きく反対していることがわかります(ただし、ネストされたメソッド定義を削除するためです)。


6
ただし、DRYnessのメソッドでクロージャラムダを作成する方法、または再帰を実行する方法を示すこともできます。
Phrogz 2011

119
Rubyにはネストされたメソッドがないのではないかと感じています。
マークトーマス

16
@Mark Thomas:Rubyにはネストされたメソッドがないことを忘れましたか?:-)真剣に:私がこの回答を書いた時点で、すでに3つの回答があり、そのすべてがRubyにネストされたメソッドあると主張ていました。それらの答えのいくつかは、露骨に間違っていたにもかかわらず、賛成票さえ持っていました。1つは、間違っていたにもかかわらず、OPによって受け入れられました。回答がRubyがネストされたメソッドをサポートしていることを証明するために使用するコードスニペットは、実際には反対のことを証明していますが、賛成派もOPも実際にチェックする必要はないようです。それで、私はすべての間違ったものに対して1つの正しい答えを与えました。:-)
イェルクWミッターク

10
これらはすべてテーブルを変更するカーネルへの単なる指示であり、メソッド、クラス、モジュールはすべてテーブルの単なるエントリであり、実際にはそうではないことに気付くと、マトリックスがどのように見えるかを見ると、Neoのようになります。そうすれば、本当に哲学的になり、ネストされたメソッド以外にメソッドすら存在しないと言うことができます。エージェントすらありません。それらはマトリックス内のプログラムです。あなたが食べているそのジューシーなステーキでさえ、テーブルの単なるエントリーです。
mydoghasworms 2013

3
メソッドはありません。コードはマトリックスのシミュレーションにすぎません
bbozo 2014

13

実際には可能です。これにはprocs / lambdaを使用できます。

def test(value)
  inner = ->() {
    value * value
  }
  inner.call()
end

2
あなたは間違っていませんが、あなたの答えはネストされたメソッドを実現するための解決策として表現されています。実際には、メソッドではないprocを使用しているだけです。「ネストされたメソッド」を解決すると主張する以外の良い答えです
Brandon Buck

5

いいえ、いいえ、Rubyにはネストされたメソッドがあります。これをチェックして:

def outer_method(arg)
    outer_variable = "y"
    inner_method = lambda {
      puts arg
      puts outer_variable
    }
    inner_method[]
end

outer_method "x" # prints "x", "y"

9
inner_methodはメソッドではなく、function / lambda / procです。どのクラスにも関連するインスタンスがないため、メソッドではありません。
Sami Samhuri 2013年

2

あなたはこのようなことをすることができます

module Methods
  define_method :outer do 
    outer_var = 1
    define_method :inner do
      puts "defining inner"
      inner_var = outer_var +1
    end
    outer_var
  end
  extend self
end

Methods.outer 
#=> defining inner
#=> 1
Methods.inner 
#=> 2

これは、メソッド間でスコープを共有する必要があるDSLを作成する場合などに役立ちます。しかし、そうでなければ、他の答えが言ったように、呼び出さinnerれるたびに再定義されるので、他のことをする方がはるかに良いですouter。この動作が必要な場合、および場合によってはそうなる可能性がある場合は、これが適切な方法です。


2

Rubyの方法は、混乱を招くハックでそれを偽造することです。これにより、一部のユーザーは「これはどのように機能するのでしょうか」と疑問に思うでしょう。RakeやRailsを使用したことがあるなら、このようなことを見たことがあるでしょう。

これがそのようなハックです:

def mlet(name,func)
  my_class = (Class.new do
                def initialize(name,func)
                  @name=name
                  @func=func
                end
                def method_missing(methname, *args)
                  puts "method_missing called on #{methname}"
                  if methname == @name
                    puts "Calling function #{@func}"
                    @func.call(*args)
                  else
                    raise NoMethodError.new "Undefined method `#{methname}' in mlet"
                  end
                end
              end)
  yield my_class.new(name,func)
end

それは、クラスを作成してそれをブロックに渡すトップレベルのメソッドを定義することです。クラスはmethod_missing、選択した名前のメソッドがあるように見せかけるために使用します。指定する必要のあるラムダを呼び出すことでメソッドを「実装」します。オブジェクトに1文字の名前を付けることで、必要な余分な入力の量を最小限に抑えることができます(これは、Railsがその中で行うのと同じことですschema.rb)。mletCommon Lisp形式にちなんで名付けられfletていfますが、「関数」を表す場合は除きます。m表す場合は「method」を表します。

あなたはそれをこのように使います:

def outer
   mlet :inner, ->(x) { x*2 } do |c|
     c.inner 12
   end
end

追加のネストなしで複数の内部関数を定義できるようにする同様の矛盾を作ることは可能ですが、それはRakeやRspecの実装で見られるようなさらに醜いハックを必要とします。Rspecのlet!動作を理解することで、そのような恐ろしい嫌悪感を生み出すことができるようになるまでの長い道のりが得られます。


-3

:-D

Rubyにはネストされたメソッドがありますが、期待どおりに機能しないだけです。

1.9.3p484 :001 > def kme; 'kme'; def foo; 'foo'; end; end              
 => nil 
1.9.3p484 :003 >   self.methods.include? :kme
 => true 
1.9.3p484 :004 > self.methods.include? :foo
 => false 
1.9.3p484 :005 > kme
 => nil 
1.9.3p484 :006 > self.methods.include? :foo
 => true 
1.9.3p484 :007 > foo
 => "foo" 

4
これはネストされたメソッドではありません...明確な理解については、JörgWMittagの回答を参照してください。
Hardik 2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.