声明并初始化范围内的类型化数组

时间:2019-05-16 05:01:17

标签: arrays range perl6 typing

我最近尝试了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

为什么会这样?

4 个答案:

答案 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中@含义的几个助记符:

  • 它看起来像 里面是0Mathematical 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';