Raku中duckmap方法的实际作用是什么?为何与deepmap表现差异大?
理解Perl 6中duckmap的行为逻辑
哈哈,这个问题确实容易搞混,我刚接触duckmap的时候也懵过!咱们一步一步拆解为什么会得到[9,9]这个结果。
核心区别:duckmap vs deepmap
首先得明确这两个方法的核心逻辑差异:
- deepmap:是「强制递归遍历」——不管当前元素是什么,只要它是可迭代(Iterable)的,就直接深入内部,直到遇到非可迭代元素,再应用你的块。这也是为什么你的测试中它的表现完全符合预期,把每个数字都平方了。
- duckmap:是「鸭子类型驱动的遍历」——它的优先级是先尝试用你的块处理当前元素:
- 如果块对当前元素执行后返回非Nil的值,就直接把这个值加入结果列表,不会再深入元素内部;
- 只有当块执行后返回Nil(也就是块“处理不了”这个元素),且元素是可迭代的,它才会递归深入元素内部继续处理。
为什么你的测试会返回[9,9]?
你的块是*²,也就是{ $_ ** 2 }的简写。当这个块作用到顶层的两个数组元素时:
- 对于
[1,2,3]:Perl 6会尝试把数组转换成数值类型来执行平方运算。在Perl 6中,数组的Numeric转换默认返回数组的元素个数(即elems方法的结果)。[1,2,3]有3个元素,所以3²=9,块成功返回9; - 对于
[[4,5],6,7]:同样,这个数组的元素个数也是3,平方后得到9,块也成功返回9。
因为块对两个顶层元素都返回了非Nil的值(9),所以duckmap直接把这两个9放进结果,完全不会去深入数组内部遍历里面的数字!
如何让duckmap像deepmap一样工作?
如果你想让duckmap递归处理所有内部数字,需要让块在遇到可迭代元素时返回Nil,触发它的深入逻辑。比如:
my $list = [[1,2,3],[[4,5],6,7]]; say $list.duckmap( -> $elem { $elem ~~ Numeric ?? $elem² !! Nil }); # 输出:[[1 4 9] [[16 25] 36 49]]
这里的逻辑很简单:如果元素是数值类型,就返回它的平方;否则返回Nil,duckmap就会自动深入这个可迭代元素内部,继续处理里面的元素。
内容的提问来源于stack exchange,提问作者jjmerelo
相关产品推荐
相关产品推荐

