我最近尝试了my Array @a = 'a'..'z';
和my Array @a = @('a'..'z');
。
两者都会产生以下错误:
Type check failed in assignment to @a; expected Array but got Str ("a")
in block <unit> at <unknown file> line 1
但是在没有类型的情况下进行初始化的工作似乎最终会产生一个Array:
> my @a = 'a'..'z';
> @a.^name
Array
为什么会这样?
答案 0 :(得分:11)
TL; DR 我在为什么会这样?中提供一个相对简单的答案。但是,该解释可能不足 1 ,所以我在声明并从范围初始化类型化数组中查看一些替代方法。
为什么会这样?
my @a;
声明一个新的Array
(初始化为空)并将其“绑定”到符号@a
。因此my @a; say @a.^name
返回Array
。无需在数组的声明或初始化中使用单词Array
-@
就足够了。 2
my @a = 'a'..'z'
尝试将'a'
到'z'
范围内的每个值一次复制,一次插入 @a[0]
,@a[1]
等。绑定到@a
的新数组对其每个元素都有类型约束(在下一节中说明);将会检查每个值(并将成功)。
my Array @a
声明一个Array
,其元素具有Array
类型约束(因此它是一个数组数组)。 my Array @a; say @a.^name
返回Array[Array]
来表明这一点。复制第一个值(a)时my Array @a = 'a'..'z';
失败,因为它是一个Str
值而不是Array
。
声明并初始化范围内的类型化数组
my @a = 'a'..'z';
此语句的my @a
部分声明了一个变量,该变量绑定到(指)类型为Array
的新数组。由于未指定任何元素类型约束,因此新数组的元素被约束为与Mu
(P6中 M ost u 假定类型)一致。换句话说,它是一个空数组,准备包含要放入其中的任何值。 (有人会说say @a.^name
会显示Array
而不是Array[Mu]
,因为[Mu]
被认为是 M ost u )
... = 'a'..'z'
初始化新数组。初始化对数组已经建立的类型约束没有影响。它只是传递字符串'a'
,'b'
等的副本。到到数组中(该数组自动展开以将它们接收到@a[0]
,@a[1]
中等)。
我建议开发人员避免在变量和显式强制值上添加显式类型约束,除非他们确信它们是理想的。 (请参见an earlier SO answer末尾的括号内的注释。)也就是说,您可以选择这样做:
my Str @a = 'a'..'z'; # `Array` elements constrained to `Str`
my Str @a = (0..99)>>.Str; # Coerce value to match constraint
或者,P6支持一个值或值列表的显式绑定,而不是赋值。最常见的方法是使用:=
代替=
:
my @a := 'a'..'z'; say @a.WHAT; say @a[25]; # (Range)z
请注意,@a
的显式绑定意味着@a
尚未绑定到新的Array
而是绑定到Range
值。而且由于Range
的行为可以像Positional
一样,所以位置下标仍然有效。
以下语句将成为完全冗余的显式键入,但两者的工作原理和结果将完全相同,尽管第一个语句会更快:
my Str @a := Array[Str].new('a'..'z');
my Str @a = Array[Str].new('a'..'z');
关于此主题还有更多要讨论的内容,但也许前面的内容足以解决此问题/答案。如果不是,请在原始问题和/或下面的评论中提出其他问题。
1 此答案的早期版本始于:
my Array @a ...
# My array of thoughts raised by this declaration
# and your questing "why?" in this SO question
# began with wry thoughts about complicated answers
# about reasons your array is awry and pedances
(我用“ pedances”这个词来形容似乎是的东西,但正确使用时流动性很好-一旦您熟悉了它的明显特质,就会自然发生实际上很有帮助。更重要的是,我需要带有“答案”押韵的内容。)
2 以下是P6中@
含义的几个助记符:
它看起来像 里面是0
(Mathematical Italic Small A)的零数字()和{{1} }变量默认为
@foo
索引的0
(或)。
它听起来像 单词“ at”。数组具有元素 at 索引。
答案 1 :(得分:7)
设置数组中元素的类型:
my Str @a = 'a'..'z';
say @a; #[a b c d e f g
要查看它是什么类型,可以使用.WHAT
my Str @a = 'a'..'z';
say @a.WHAT #(Array[Str])
要测试它是否为数组,可以进行智能匹配
my Str @a = 'a'..'z';
say 'is array' if @a ~~ Array; #is array
say 'is str array' if @a ~~ Array[Str]; #is str array
say 'is str array' if @a ~~ Array[Int]; #
答案 2 :(得分:7)
@('a'..'z')
将使List
而不是Array
。更改为
['a'..'z']
将给出Array
。
但是当您将其分配给my Array @a
时,仍然会产生类型错误。
如果要将整个数组分配给另一个数组的元素,则必须以某种方式逐项列出,例如:
$[1,2,3]; #Still an array but treated as single item
[1,2,3], ; #Note the list operator (comma), this give you a list of lists
所以在您的情况下:
'a'..'z';
是一个范围,需要转换为数组,所以
['a'..'z'];
范围现在被评估为一个数组
$['a'..'z'];
范围现在被评估为一个数组,并作为单个项目
my Array @a=$['a'..'z'];
say @a;
#OUTPUT:
#[[a b c d e f g h i j k l m n o p q r s t u v w x y z]]
# Which is an array of arrays;
不确定是不是您想要的,但是它会消除类型错误。
答案 3 :(得分:0)
声明数组时,可以轻松指定数组元素的类型。
my Str @a = 'a'..'z';
您还可以指定用于存储的确切类。
下一行与上一行完全相同;因为Array
是默认存储类。
my @a is Array[Str] = 'a'..'z';
您甚至可以将两者结合在一起。
以下内容也完全相同。
my Str @a is Array = 'a'..'z';
当您编写以下行时。
my Array @a = 'a'..'z';
您实际上在说的是:
my @a is Array[Array] = 'a'..'z';
我想你以为你在写这篇文章。
my @a is Array = 'a'..'z';
如果您不想更改元素,这将很有用。
my @a is List = 'a'..'z';
或者,如果您有默认Array
类无法满足的特定需求。
use Array::Unique; # doesn't really exist yet (afaik)
my @a is Array::Unique[Str] = 'a'..'z';
my Str @b is Array::Unique = 'a'..'z';