Ruby 有可能在方法中包含方法吗?

Ruby 有可能在方法中包含方法吗?,ruby,methods,Ruby,Methods,我在一个方法中有一个方法。内部方法取决于正在运行的变量循环。这是一个坏主意吗?更新:由于这个答案最近似乎引起了一些兴趣,我想指出有 不,Ruby没有嵌套方法 您可以这样做: class Test1 def meth1 def meth2 puts "Yay" end meth2 end end Test1.new.meth1 def outer mlet :inner, ->(x) { x*2 } do |c| c.inne

我在一个方法中有一个方法。内部方法取决于正在运行的变量循环。这是一个坏主意吗?

更新:由于这个答案最近似乎引起了一些兴趣,我想指出有


不,Ruby没有嵌套方法


您可以这样做:

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

Test1.new.meth1
def outer
   mlet :inner, ->(x) { x*2 } do |c|
     c.inner 12
   end
end
但这不是一个嵌套的方法。我重复一遍: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非常反对嵌套方法(但仍然支持删除嵌套方法定义)。

不,不,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"
:-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" 

你可以这样做

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时,这非常有用。但除此之外,您最好做其他事情,因为正如其他答案所说,
internal
在调用
outer
时被重新定义。如果你想要这种行为,而且有时可能,这是一种很好的方法。

实际上这是可能的。您可以使用procs/lambda进行此操作

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

Ruby的方法是用令人困惑的黑客来伪装它,这会让一些用户疑惑“这到底是怎么回事?”,而不那么好奇的人只会记住使用它所需的语法。如果你曾经用过耙子或铁轨,你也见过这种东西

这里有这样一个黑客:

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\u missing
来假装它有一个具有您选择的名称的方法。它通过调用必须提供的lambda来“实现”该方法。通过使用一个字母的名称命名对象,可以最大限度地减少它所需的额外键入量(这与Rails在其
schema.rb
中所做的相同)
mlet
是以常见的Lisp格式
flet
命名的,除非
f
代表“函数”,
m
代表“方法”

您可以这样使用它:

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

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

可以制作一个类似的装置,允许在没有额外嵌套的情况下定义多个内部函数,但这需要一种更难看的黑客,就像在Rake或Rspec的实现中一样。弄清楚Rspec的
let
works将使您能够创建如此可怕的令人憎恶的东西。

您能否共享代码示例或至少与您尝试执行的操作具有同等逻辑意义的代码。不过,您也可以演示如何在干燥方法中创建闭包lambda,或者运行递归。我感觉Ruby可能没有嵌套方法。@Mark Thomas:我忘了提到Ruby没有嵌套方法了吗?:-)严肃地说:在我写这个答案的时候,已经有三个答案了,每一个都声称Ruby确实有嵌套的方法。其中一些答案尽管明显错误,但仍获得了支持票。一个甚至被OP再次接受,尽管是错误的。answer用来证明Ruby支持嵌套方法的代码片段实际上证明了相反的结果,但显然Upvorts和OP都没有费心去检查。所以,我对每一个错误都给出了一个正确的答案。:-)当您意识到这些都只是内核修改表的指令,方法、类和模块都只是表中的条目,而不是真正的实体时,当Neo看到矩阵的样子时,您就会变得像Neo一样。然后你可以真正变得哲学化,说除了嵌套的方法,甚至没有方法。甚至连特工都没有。它们是矩阵中的程序。即使是你正在吃的美味牛排也只是表格中的一个条目。没有方法,你的代码只是Matrixinner_中的一个模拟。方法不是一个方法,它是一个函数/lambda/proc。没有任何类的关联实例,因此它不是方法。这不是嵌套方法。。。请参阅Jörg W Mittag的答案以获得清晰的理解。您没有错,但您的答案是作为实现嵌套方法的解决方案。实际上,您只是在使用不是方法的过程。除了声称解决“嵌套方法”之外,这是一个很好的答案