【问题标题】:Declare and initialize a typed array from a range从一个范围声明并初始化一个类型化数组
【发布时间】:2019-05-16 05:01:17
【问题描述】:

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

但是没有类型的初始化是可行的,并且似乎最终会产生一个数组:

> my @a = 'a'..'z';
> @a.^name
Array

为什么会这样?

【问题讨论】:

  • 我猜当你输入一个数组时,该类型适用于数组中的每个元素。因此,在您的情况下,每个元素的类型不是Array,而是Str。这就是为什么当您将@a 输入为my Array @a 时会收到错误expected Array but got Str

标签: arrays range raku typing


【解决方案1】:

TL;DR我在为什么会这样?中提供了一个相对简单的答案,但是,这种解释可能不够充分1,所以我查看从范围声明和初始化类型化数组中的一些替代方法。

为什么会这样?

  • my @a; 声明一个新的Array(初始化为空)并将其“绑定”到符号@a。因此my @a; say @a.^name 返回Array。不需要在数组的声明或初始化中使用 Array 这个词——@ 就足够了。2

  • my @a = 'a'..'z' 尝试复制'a''z' 范围内的每个值,一次一个,复制@a[0],@ 987654337@ 等。绑定到@a 的新数组对其每个元素都有一个类型约束(在下一节中解释);它将检查每个值(并且会成功)。

  • my Array @a 声明了一个Array,其元素具有Array 类型约束(因此它是一个数组数组)。 my Array @a; say @a.^name 返回 Array[Array] 以表明这一点。 my Array @a = 'a'..'z'; 在复制第一个值 ("a") 时失败,因为它是 Str 值而不是 Array

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

my @a = 'a'..'z';

该语句的my @a 部分声明了一个变量,该变量绑定到(引用)一个Array 类型的新数组。因为没有指定元素类型约束,所以新数组的元素被约束为与 P6 中的 Most un假设类型 Mu 一致。换句话说,它是一个空数组,可以包含您想要放入的任何值。 (可以说say @a.^name 显示Array 而不是Array[Mu],因为[Mu] 被认为是Most uninteresting。)

... = '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 一样工作,所以位置下标仍然有效。

以下语句在 imo 中是非常多余的显式类型,但它们都可以工作并产生完全相同的结果,尽管第一个语句会更快:

my Str @a := Array[Str].new('a'..'z'); 
my Str @a  = Array[Str].new('a'..'z'); 

关于这个话题还有很多要讨论的,但也许前面的内容足以解决这个问题/答案。如果没有,请在您的原始问题下方和/或下方在 cmets 中提出更多问题。

脚注

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) -- 并且 @foo 变量默认是 @987654376 @索引?????(或@????)。

  • 听起来像“at”这个词。数组有元素索引。

【讨论】:

    【解决方案2】:

    设置数组中元素的类型:

    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])
    

    判断是否为数组,可以smartmatch

    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]; #
    

    【讨论】:

      【解决方案3】:

      @('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;
      

      不确定它是否是您所追求的,但它消除了类型错误。

      【讨论】:

        【解决方案4】:

        当你声明一个数组时,你可以很容易地指定数组的元素是什么类型。

        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';
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-10-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-04-05
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多