Ruby Lambda vs.Proc LocalJumpError

Ruby Lambda vs.Proc LocalJumpError,ruby,proc-object,Ruby,Proc Object,Ruby和StackOverflow新手在Ruby中工作,遇到了我的第一个主要障碍。我真的很难把我的头缠在Procs和Lambdas上。这是我正在使用的代码 def procBuilder(message) Proc.new{ puts message; return} end def test puts "entering method" p = procBuilder("entering proc") p.call puts "exit method" end tes

Ruby和StackOverflow新手在Ruby中工作,遇到了我的第一个主要障碍。我真的很难把我的头缠在Procs和Lambdas上。这是我正在使用的代码

def procBuilder(message)
  Proc.new{ puts message; return}
end

def test
  puts "entering method"
  p = procBuilder("entering proc")
  p.call
  puts "exit method"
end

test
根据设计,这是抛出一个LocalJumpError,但我不明白为什么。如果我不得不猜测这是怎么回事,我会猜测它最初会在运行p=procBuilder(“entering proc”)时打印“entering proc”,然后在p.call上抛出一个错误,因为p.call没有传递任何字符串,但很明显,我遗漏了这两行之间发生的一些关键内容。我也不完全理解为什么它与lambda而不是proc一起工作,但我认为理解错误也能解决这个问题

提前感谢您的澄清

以下是我对一个相关问题的回答。它讨论了lambda vs proc和LocalJumpErrors

在proc中,
return
是一种特殊的语法,它从proc的词法范围返回,而不是从proc本身返回。因此,它试图从已经退出的
procBuilder
中返回

有几种方法可以解决此问题:

  • 根本不要使用
    return
    。Ruby将自行将控制权返回给proc的调用方
  • proc
    更改为
    lambda
    ,其行为符合您的预期。Lambdas的行为类似于方法;过程就像块一样
  • 至于你所期望的错误,你不应该得到它
    procBuilder
    返回包含消息变量的proc。进程本身不需要任何参数

    编辑:回答您的附加问题。这个过程是一个结束。它“捕获”了消息变量(procBuilder中的局部变量),该变量在创建proc时在范围内。proc现在可以在程序中漫游,其中隐藏了消息变量,可以在调用它时打印出来。唯一的问题是return语句,它还有一个额外的要求,即它的词法范围仍然是“live”

    这一切的原因是,这种行为在块中非常有用。在这种情况下,它没有任何帮助,所以您应该只使用
    lambda
    ,其中return表示不那么疯狂的东西


    关于ruby中闭包的一个非常好的教程:

    proc和方法或lambda之间的一个重要区别是它们处理return语句的方式。如果在另一个方法中定义了一个方法,则内部方法中的return语句仅从内部方法本身退出,然后外部方法继续执行。在lambda中定义lambda、在方法中定义lambda或在lambda中定义方法也是如此。但是,当在方法中定义过程时,return语句将与外部(封闭)方法一样从过程中退出。例如:

    def meditate
        puts "Adjusting posture…"
        p = Proc.new { puts "Ringing bell…"; return }
        p.call
        puts "Sitting still…"  # This is not executed
    end
    
    meditate
    
    Output:
    Adjusting posture…
    Ringing bell…
    
    请注意,由于proc中的return语句已从proc和封闭方法退出,因此方法的最后一行是如何未执行的

    如果我们定义一个没有封闭(外部)方法的proc并使用return语句,它将抛出LocalJumpError

    p = Proc.new { puts "Ringing bell…"; return }
    p.call
    Output:
    Ringing bell…
    LocalJumpError: unexpected return
    
    这是因为当在proc中到达return语句时,它不是从调用它的上下文返回,而是从定义它(proc)的范围返回。在下面的示例中,发生LocalJumpError是因为proc试图从定义它的顶级环境返回

    def meditate p
        puts "Adjusting posture…"
        p.call
        puts "Sitting still…"  # This is not executed
    end
    
    p = Proc.new { puts "Ringing bell…"; return }
    
    meditate p
    Output:
    Adjusting posture…
    Ringing bell…
    LocalJumpError: unexpected return
    
    通常,在proc中使用return语句不是一个好主意。proc通常在方法之间传递,如果定义proc的方法已经返回,它将抛出异常。在下面的示例中,我们可以删除return语句。然而,有些情况下我们确实需要归还一些东西。在后者中,最好使用lambda而不是proc。稍后我们将看到,lambdas以不同的方式处理返回语句,更像方法

    下面是涉及return语句的另一个场景:

    def zafu_factory
        # This method will return the following proc implicitly
        Proc.new { puts "Round black zafu"; return }
    end
    
    def meditate
        puts "Adjusting posture…"
        p = zafu_factory
        p.call
        puts "Sitting still…"  # This is not executed
    end
    
    meditate
    Output:
    Adjusting posture…
    Round black zafu
    LocalJumpError: unexpected return
    
    刚才发生了什么事?zafu_工厂方法创建并隐式返回一个proc。然后,冥想方法调用proc,当到达proc中的return语句时,它尝试从定义它的上下文返回(zafu_工厂方法)。但是,zafu_工厂已经返回了proc,并且方法每次调用只能返回一次。换句话说,抛出异常是因为调用proc时zafu_工厂方法已经返回,并尝试第二次返回


    在这篇关于

    的博文中可以看到更多信息,如果我错了,请纠正我,但我认为这与
    return
    语句有关<过程中的code>return也将尝试从调用方法返回。因此,
    p.call
    尝试从
    test
    以及
    procbuilder
    返回,谢谢Isaac,但我还是有点模糊。当你说“从调用proc的方法返回的特殊语法片段,而不是proc本身”时,你是在告诉我它跳到了测试方法的末尾和程序的末尾,对吗?为什么这是一个错误,而不仅仅是程序的结束?再次感谢您的帮助,但我仍然在挣扎(相信我,我已经彻底地把头撞到了墙上)。如果proc在到达p.call之前已经运行并返回,因此测试方法已从中返回,那么p.call如何能够将“进入proc”打印到控制台?我编辑了一点。我不得不修改一下原始答案,然后回答了你的附加问题我想我或多或少都明白了,也许术语“LocalJumpError”本身只是给我一个循环。谢谢你的帮助。