メソッドの中にメソッドがあります。内点法は、実行されている変数ループに依存します。それは悪い考えですか?
回答:
更新:この回答は最近関心を集めているようですので、ここで説明した機能を削除する、つまりメソッド本体内にメソッド定義を含めることを禁止するための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がネストされたメソッドに大きく反対していることがわかります(ただし、ネストされたメソッド定義を削除するためです)。
実際には可能です。これには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
Common Lisp形式にちなんで名付けられflet
ていf
ますが、「関数」を表す場合は除きます。m
表す場合は「method」を表します。
あなたはそれをこのように使います:
def outer
mlet :inner, ->(x) { x*2 } do |c|
c.inner 12
end
end
追加のネストなしで複数の内部関数を定義できるようにする同様の矛盾を作ることは可能ですが、それはRakeやRspecの実装で見られるようなさらに醜いハックを必要とします。Rspecのlet!
動作を理解することで、そのような恐ろしい嫌悪感を生み出すことができるようになるまでの長い道のりが得られます。
:-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"