メソッドの中にメソッドがあります。内部メソッドは、実行されている変数ループに依存します。それは悪い考えですか?
更新:この答えは最近興味を持っているように見えるので、 Discussion on the Ruby issue tracker to removeここで説明した機能、つまりforbidメソッド本体内にメソッド定義を含む 。
いいえ、Rubyにはネストされたメソッドはありません。
次のようなことができます:
class Test1
def meth1
def meth2
puts "Yay"
end
meth2
end
end
Test1.new.meth1
しかし、それはnotネストされたメソッドです。繰り返します:Rubydoes not havenested method。
これは、動的なメソッド定義です。 meth1
を実行すると、meth1
の本体が実行されます。本文はたまたまmeth2
という名前のメソッドを定義しているため、meth1
を1回実行した後、meth2
を呼び出すことができます。
しかし、meth2
はどこで定義されていますか?さて、それは明らかにnotnot(-===-)です。なぜなら、noRubyのネストされたメソッド。 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では、メソッド本体はクロージャーにはできず、ブロック本体のみがクロージャーになることに注意してください。 ifRubyサポートされているネストされたメソッド、 tネストされたメソッドで外部メソッドの変数を使用します。
UPDATE CONTINUED:later段階で、この構文はネストされたメソッドをRubyに追加するために再利用される可能性があり、これは私が説明した方法で動作します:それらは包含メソッドにスコープされます。つまり、包含メソッド本体の外側では見えず、アクセスできません。そしておそらく、それらは含まれるメソッドのレキシカルスコープにアクセスできるでしょう。ただし、上記でリンクした説明を読むと、matzがネストされたメソッドに大きく反していることがわかります(ただし、ネストされたメソッド定義を削除するために)。
実際には可能です。これにはprocs/lambdaを使用できます。
def test(value)
inner = ->() {
value * value
}
inner.call()
end
いいえ、いいえ、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"
このようなことができます
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
が再定義されるため、他のことを行う方がはるかに適切です。この動作が必要な場合、および場合によっては、これを取得するのに適した方法です。
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
で行うことと同じです)。mlet
は、flet
が「関数」を表し、f
が「メソッド」を表すことを除いて、Common LISP形式m
にちなんで命名されます。
次のように使用します。
def outer
mlet :inner, ->(x) { x*2 } do |c|
c.inner 12
end
end
ネストを追加せずに複数の内部関数を定義できる同様の仕掛けを作成することもできますが、RakeまたはRspecの実装で見られるようなsortいハックが必要になります。 Rspecのlet!
がどのように機能するかを理解することで、このような恐ろしい憎悪を生み出すことができるようになります。