如何从非Routine类型块的CATCH phaser中返回值?
非Routine块的CATCH Phaser中返回值的正确语法
咱们先拆解你遇到的问题:在map这类非Routine的匿名块里,想用CATCH处理异常后返回指定值,但直接写返回值得不到结果,用return又报错,对吧?
先分析你给出的两个示例:
示例1:foo()的问题
sub foo() { <1 2 3>.map: -> $a { die 'oops'; CATCH { default { 'foo' } } } }
执行后输出(Nil, Nil, Nil),原因很简单:当块里触发die后,CATCH块确实处理了异常,但CATCH的返回值并不会自动成为当前块的返回值——原块的执行已经被die中断,默认情况下这个块会返回Nil。
示例2:bar()的问题
sub bar() { <1 2 3>.map: -> $a { die 'oops'; CATCH { default { return 'bar' } } } }
执行时报错Attempt to return outside of immediately-enclosing Routine,这是因为裸的return关键字是用来返回最近的Routine(比如sub、method这类明确的例程),而map的匿名块不属于Routine范畴,所以return找不到对应的动态作用域,直接抛出错误。
正确的语法
要在非Routine块的CATCH里让当前块返回指定值,你需要使用$?BLOCK.return(你的值)的方式——$?BLOCK是当前块的内置变量,调用它的return方法可以明确让这个块返回给定的值,不会去寻找外层的Routine。
修正后的示例代码:
sub baz() { <1 2 3>.map: -> $a { die 'oops'; CATCH { default { $?BLOCK.return('baz') } } } } say baz(); # 输出 (baz baz baz)
另外补充个小知识点:如果die之后还有代码需要执行,你可以用resume来恢复执行,但在你的场景里die之后没有后续代码,所以用$?BLOCK.return()是最直接的解决方案。
内容的提问来源于stack exchange,提问作者J Hall
相关产品推荐
相关产品推荐

