这是Perl 6 Hash还是Block?

问题描述 投票:9回答:2

这有点意外的行为,可能会咬人初学者。首先,这是打算吗?其次,Perl 6使用什么来猜测要创建哪个对象?它是否开始认为它是Block或Hash并稍后更改,还是最终决定?

你可以构建一个带括号和胖箭头的Hash

my $color-name-to-rgb = {
    'red' => 'FF0000',
    };

put $color-name-to-rgb.^name;  # Hash

使用另一个Pair符号也会创建一个Hash

my $color-name-to-rgb = {
    :red('FF0000'),
    };

但是,没有胖箭,我得到一个Block代替:

my $color-name-to-rgb = {
    'red', 'FF0000',
    };

put $color-name-to-rgb.^name;  # Block

Hash文档只提到在括号内使用$_创建一个Block

还有其他方法来定义哈希,但我问的是这个特定的语法,而不是寻找我已经知道的解决方法。

$ perl6 -v
This is Rakudo version 2017.04.3 built on MoarVM version 2017.04-53-g66c6dda
implementing Perl 6.c.
hash block perl6 raku
2个回答
11
投票

首选的Perl6方法是使用%( )创建哈希。

my $color-name-to-rgb = %(
    'red', 'FF0000',
    );

我不建议人们使用大括号来创建哈希。如果他们想要制作哈希,那么%( )就是这样做的正确方法。

如果你来自Perl 5世界,最好养成在创建哈希时使用%( )而不是{ }的习惯。


11
投票

TL; DR这个答案从我认为合理的最简单的描述开始,然后尝试以精确的细节覆盖所有内容。如果有任何问题太复杂或缺失,请在评论中告诉我。

This rule only applies in term position

只有术语position1中的支撑代码({...})才能使用此DWIM / WAT.2

在这些例子中,{...}不是术语位置:

if True { ... }   # always a block
class foo { ... } # always a package
put bar{ ... }    # always a hash index

对于本答案的其余部分,{...}仅表示术语位置的支撑代码。

Simple description of DWIM/WAT for {...} in term position

  1. 默认情况下,{...}Block。此外,如果它有签名,多个语句或标识符的声明,那么它就是Block
  2. 否则,如果{...}只包含零个或多个值的列表,直接从% sigil'd变量(例如%foo)或Pair文字(例如:bar)开始,那么它就是Hash

A signature means it's a Block

一些支撑代码具有显式签名,即它具有明确的参数,例如下面的$foo。它总是构造一个Block,无论大括号里面是什么:

say WHAT         { key => $foo, 'a', 'b' } # (Hash)
say WHAT -> $foo { key => $foo, 'a', 'b' } # (Block)

一些支撑代码具有隐式签名:

  • 在支撑代码中使用显式占位符变量(例如$^foo)会给它一个隐式签名(其中包含$foo参数)。
  • 在支撑代码中使用代词即使它没有明确的代码也会给它一个签名。代词是$_@_%_
  • 由于{ .foo },甚至(;; $_? is raw)也有签名(.foo)。

与显式签名一样,如果支持的代码具有隐式签名,那么无论大括号内部是什么,它总是构造一个Block

say WHAT { key => $_, 'a', 'b' }           # (Block)
say WHAT { key => 'value', .foo, .foo }    # (Block)

Multiple top level statements mean it's a Block

say WHAT { :foo; (do 'a'), (do 'b') }     # (Block)
say WHAT { :foo, (do 'a'), (do 'b') }     # (Hash)

第二行包含多个语句,但它们在列表中生成值,这是单个顶级语句。

A top level declaration of an identifier mean it's a Block

say WHAT { :foo, (my $bar), $baz }        # (Block)
say WHAT { :foo, {my $bar}, $baz }        # (Hash)

最后一行包含一个Block作为包含声明(my $bar)的键。但该声明属于内部Block,而不是外部支撑代码。因此,就外部支撑代码而言,内部Block只是一个值,因此外部支撑块仍然被解释为Hash

Still Blocks

my $bar = key => 'value';
say WHAT         { $bar, %baz }            # (Block)
say WHAT         { |%baz      }            # (Block)
say WHAT         { %@quux     }            # (Block)

以上都不是以% sigil'd变量或字面对开头的。

When it's a Hash

不属于任何前述情况的强制代码强制它成为Block,并且它只是一个零或更多值的列表,以% sigil'd变量或Pair文字结构构成Hash

say WHAT { %foo      }                    # (Hash)
say WHAT { %foo, ... }                    # (Hash)
say WHAT { foo => 42, ... }               # (Hash)
say WHAT { :foo, ... }                    # (Hash)
say WHAT { key => $foo,  'a', 'b'      }  # (Hash)
say WHAT { 'a', 'b',      key => $foo  }  # (Block)

上面的最后一个块不是以%foo或文字对开头的。

say WHAT { %foo,         'a', 'b'      }   # (Hash)
say WHAT { Pair.new('key',$foo),           # Pair.new is NOT a literal
           'a', 'b'                    }   # (Block)

上面的第二个块不是以%foo或文字对开头。

To force Block or Hash interpretation

  • 要写一个空的Block,写下{;}。要写一个空的Hash,写下{}
  • 要强制支撑代码构造Block而不是Hash,请在开头写一个;,即{; ... }
  • 要强制支撑代码构造Hash而不是Block,请遵循上面解释的规则或写%(...)而不是{...}

Footnotes

1请参阅以下评论关于学期位置的评论。

2大多数时候,一个有价值的DWIM必须在大多数编码人员的帮助下工作,其相关的WATs必须为社区所接受。 (当DWIM没有达到他们的意思时,WAT指的是开发者的惊喜。对于每个DWIM,都有一个或多个WAT。)

可接受的WAT有barks worse than their bites。像所有的DWIM一样,这个可以要求community vigilance and response确保它仍然是一个净赢,而不是保证弃用,社区成员的意见不同,它的咬伤程度。 cf my perspective vs Sam对这个问题的回答。

© www.soinside.com 2019 - 2024. All rights reserved.