给定一个参数,Array
构造函数将其展平。这会导致问题:
my %hash = (a => 1; b => 2);
my @array = [ %hash ]; # result: [a => 1 b => 2], expected [{ a => 1, b => 2 }]
List构造函数没有这个怪癖(single-argument rule),但不幸的是,创建单元素列表没有简短的语法:
List.new(%hash); # result is ({a => 1, b => 2}), as expected
解决方法:如果您的参数是标量,则不会自动展平:
my $hash = %hash;
my @array = [ $%hash ]; # or my @array = [ $%hash ], or just my @array = $%hash
# result: [{a => 1, b => 2}], as expected
另一种解决方法是在元素列表的末尾添加逗号:
my @array = [ %hash, ];
真正的问题是我们按字面意思写出数据。如果单元素列表被展平,则在Perl 6中表示类似JSON的嵌套结构是一个真正的问题,但其他列表则不是。数据最终是错误的。使用MongoDB时我必须写出大量数据,因为MongoDB API参数必须格式化为嵌套列表/数组。这几乎是不可能的。所以我问,扁平化单个数组元素的动机是什么?
答案 0 :(得分:9)
展平单个数组元素的动机是始终如一地应用单个参数规则。数组构造函数[ ]
也遵循单个参数规则。也许有必要将[%h]
视为infix:<[ ]>(%h)
,它实际上是。如果您不想展平,可以将其逐项列出($
前缀),或者如您所示,添加逗号以使其成为List
。这遵循与($a)
与$a
相同的逻辑,但($a,)
是List
,其中包含一个元素$a
。
my %h = a => 42, b => 666;
dd [%h]; # [:a(42), :b(666)]
dd [%h,%h]; # [{:a(42), :b(666)}, {:a(42), :b(666)}]
dd [%h,] # [{:a(42), :b(666)},] make it a List first
dd [$%h] # [{:a(42), :b(666)},] itemize the Hash
答案 1 :(得分:7)
Perl中的@ sigil表示&#34;这些&#34;,而$表示&#34;&#34;。这种复数/单一的区别出现在语言的各个地方,Perl的很多便利来自它。扁平化是指在某些情况下,类似@的东西会将其值自动合并到周围列表中。 传统上,这一直是Perl强大和混乱的源泉。 Perl 6在演变过程中经历了许多与扁平化有关的模型,然后在一个简单的模型上进行了解决,即&#34;单个参数规则&#34;。
通过考虑for循环将执行的迭代次数,可以最好地理解单个参数规则。迭代的东西总是被视为for循环的单个参数,因此是规则的名称。
for 1, 2, 3 { } # List of 3 things; 3 iterations
for (1, 2, 3) { } # List of 3 things; 3 iterations
for [1, 2, 3] { } # Array of 3 things (put in Scalars); 3 iterations
for @a, @b { } # List of 2 things; 2 iterations
for (@a,) { } # List of 1 thing; 1 iteration
for (@a) { } # List of @a.elems things; @a.elems iterations
for @a { } # List of @a.elems things; @a.elems iterations
来自Synopsis7 https://design.perl6.org/S07.html#The_single_argument_rule
答案 2 :(得分:5)
@a,
构造一个单元素List
,因此当将该表达式的结果传递给列表转换运算符时,它会将List
视为对待任何其他非运算符容器化Iterable
传递给它:它迭代它,并对其元素进行操作。$
变量)中时,参数不会被迭代,这意味着保留单数复数的区别正如@p6steve's answer所解释的那样,这些印记。这里是前面提到的一致性,使用一个关键字,一个二元运算符和一个外接运算符进行演示:
for @a { ... } # n iterations
for @a, { ... } # 1 iteration
for @a, @b { ... } # 2 iterations
for $a { ... } # 1 iteration
1..Inf Z @a # new Seq of n elements
1..Inf Z @a, # new Seq of 1 element
1..Inf Z @a, @b # new Seq of 2 elements
1..Inf Z $a # new Seq of 1 element
[ @a ] # new Array with n elements
[ @a, ] # new Array with 1 element
[ @a, @b ] # new Array with 2 elements
[ $a ] # new Array with 1 element
这些 do 具有参数列表,因此单参数规则并不像它对运算符那样自然。
请注意,在参数列表的顶级范围内,逗号不会创建List
- 它们会分隔参数。
被考虑的子程序/方法&#34;列表转换&#34;期望潜在嵌套列表作为输入的例程仍然参与单一规则规则,通过检查它们是否有一个参数或多个,如果只有一个,是否包含在一个项容器中:
map {...}, @a; # n iterations
map {...}, (@a,); # 1 iteration (Parens needed to get a List-constructing comma.)
map {...}, @a, @b; # 2 iterations
map {...}, $a; # 1 iteration
用户定义的例程可以使用+@
签名轻松获取此行为。