我在方法中有一个方法。内部方法依赖于正在运行的变量循环。这是个坏主意吗?
答案 0 :(得分:154)
更新:由于这个答案最近似乎引起了一些兴趣,我想指出有discussion on the Ruby issue tracker to remove the feature discussed here, namely to forbid having method definitions inside a method body。
不,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中,方法体不能是闭包,只能是块体。这几乎消除了嵌套方法的主要用例,因为即使 if Ruby支持嵌套方法,也不能在嵌套方法中使用外部方法的变量。
UPDATE CONTINUED:在以后的阶段,然后,这个语法可能会重新用于向Ruby添加嵌套方法,这将按照我所描述的方式运行:它们的作用域将包含在其包含的方法中,即在其包含方法体外的不可见和不可访问。并且可能,他们可以访问其包含方法的词法范围。但是,如果您阅读我上面链接的讨论,您可以观察到matz严重违反嵌套方法(但仍然用于删除嵌套方法定义)。
答案 1 :(得分:10)
实际上它是可能的。你可以使用procs / lambda。
def test(value)
inner = ->() {
value * value
}
inner.call()
end
答案 2 :(得分: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"
答案 3 :(得分:1)
你可以做这样的事情
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
。如果你想要这种行为,有时你可能会这样做,这是获得它的好方法。
答案 4 :(得分:0)
Ruby的方法是用令人困惑的黑客来伪造它,让一些用户想知道"他妈的如何做到这一点?",而不那么好奇只会记住使用事情。如果您曾经使用过Rake或Rails,那么您已经看过这种事情。
这是一个黑客攻击:
wc -l
它的作用是定义一个创建类并将其传递给块的顶级方法。该类使用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
假装它具有您选择的名称的方法。它"实现"通过调用必须提供的lambda方法。通过使用单个字母的名称命名对象,可以最大限度地减少所需的额外输入量(这与Rails在method_missing
中执行的操作相同)。 schema.rb
以Common Lisp表单mlet
命名,除了flet
代表"函数",f
代表"方法&#34 ;
你这样使用它:
m
可以制作一个类似的装置,允许定义多个内部函数而无需额外的嵌套,但这需要一个更糟糕的黑客,你可能会在Rake或Rspec的实现中找到它。弄清楚Rspec的def outer
mlet :inner, ->(x) { x*2 } do |c|
c.inner 12
end
end
如何运作会让你在创造如此可怕的憎恶方面有很长的路要走。
答案 5 :(得分:-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"