问题的背景:
切片(slices)是 Perl 的一个强大特性,允许在一次操作中提取或赋值数组或哈希中的一组元素。切片机制几乎从 Perl 的第一个版本就存在,支持类似于 Python 的语法,但具有执行和上下文的独特特点。
问题:
切片的主要难点在于区分数组和哈希的切片、它们的标量/列表上下文、通过切片赋值时的“细微”差异(特别是当赋值到同一个数组或哈希时,或使用重复的索引时)。一个重要的点是,如果通过切片更新结构,容易因列表的自动扩展而意外获得不明显的结果。
解决方案:
只在有意识的情况下使用切片。如有必要复制数据,请使用显式的列表克隆。在读取和写入过程中避免交叉,并明确关注标量/列表上下文,如果切片作为函数参数或表达式中的元素使用时。
代码示例:
my @array = (10, 20, 30, 40, 50); my @slice = @array[1, 3]; # (20, 40) @array[0, 2] = (100, 300); # @array 现在是 (100, 20, 300, 40, 50) my %hash = (foo => 1, bar => 2, baz => 3); my @vals = @hash{"foo", "baz"}; # (1, 3)
关键特性:
陷阱问题 1: 是否可以从切片 @array[2, 4] 中获取“标量”值,比如 $val = @array[2, 4]?
不可以,$val 在这种情况下等于元素个数(列表的长度),而不是单个元素的值。正确的方式是通过单个索引访问:$array[2]。
陷阱问题 2: 如果切片中有重复索引,会赋值什么?
顺序重赋值:从左到右,对每个索引执行赋值,最后一个胜出。例如:
@array[0,0] = (1,2); # $array[0] == 2
陷阱问题 3: 是否可以为切片赋值,其中左右元素数量不同?
可以,如果右侧元素较少,剩余的将得到 undef。如果更多,则多余的被忽略。通常这是难以发现错误的源头。
开发人员赋值: @array[2, 3] = ("foo");
预期两个元素都获得 "foo",但 $array[3] 变成了 undef。
优点:
缺点:
使用 map 函数来映射值: @array[2, 3] = map { "foo" } (2, 3);
优点:
缺点: