内部方法有可能吗?
我有一个方法里面的方法。 内部方法取决于正在运行的variables循环。 这是一个坏主意吗?
更新:由于这个答案最近似乎已经引起了一些兴趣,我想指出的是,有关Ruby问题跟踪器的讨论删除了这里讨论的function,即禁止方法体内的方法定义 。
不,Ruby没有嵌套的方法。
你可以做这样的事情:
class Test1 def meth1 def meth2 puts "Yay" end meth2 end end Test1.new.meth1
但是这不是一个嵌套的方法。 我再说一遍:Ruby 没有嵌套的方法。
这是什么,是一个dynamic的方法定义。 当运行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中,方法体不能被closures,只有块体可以。 这几乎消除了嵌套方法的主要用例,因为即使Ruby支持嵌套方法,也不能在嵌套方法中使用外部方法的variables。
更新继续:在稍后的阶段,这个语法可能被重新用于向Ruby添加嵌套的方法,这将按照我所描述的方式进行:它们将被限制到它们的包含方法,即在它们的包含方法之外是不可见的和不可访问的身体。 可能的话,他们可以访问其包含的方法的词汇范围。 但是,如果您阅读上面讨论的链接,则可以发现matz严重违反嵌套方法(但仍然用于删除嵌套方法定义)。
其实这是可能的。 你可以使用这个/ proc / 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时,这很有用。 但是除此之外,你做任何事情都会好得多,因为正如其他答案所说的那样,只要调用outer
就会重新定义inner
。 如果你想要这样的行为,而且有时你可能会这样做,那么这是一个很好的方法。
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
所做的是定义一个顶级的方法,创build一个类并将其传递给一个块。 该类使用method_missing
假装它具有您select的名称的方法。 它通过调用你必须提供的lambda来“实现”方法。 通过用一个单字母名称命名对象,可以最大限度地减less所需的额外键入量(这与Rails在其schema.rb
所做的相同)。 除了f
代表“function”, m
代表“method”以外, mlet
是以Common Lisp form flet
命名的。
你这样使用它:
def outer mlet :inner, ->(x) { x*2 } do |c| c.inner 12 end end
有可能做一个类似的工具,允许定义多个内部函数而无需额外的嵌套,但是这需要在Rake或Rspec的实现中可能发现的那种更加丑陋的黑客攻击。 搞清楚Rspec的让步let!
作品会让你在创造如此可怕的可憎之物方面有很长的路要走。
😀
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"