这是Perl 6 Hash还是Block?

时间:2017-05-21 20:21:01

标签: hash block perl6 raku

这是一种可能会引发初学者的意外行为。首先,这是打算吗?其次,Perl 6使用什么来猜测要创建哪个对象?是开始认为它是阻止还是哈希并稍后更改,还是决定结束?

您可以使用大括号和胖箭头构建Hash

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

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

使用其他配对符号也会创建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.

2 个答案:

答案 0 :(得分:11)

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

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

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

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

答案 1 :(得分:10)

TL; DR 有几个简单的规则。他们自然地工作。简单的解释听起来很复杂。因此,这个答案也提供了一个极其详尽的答案,其中详细说明了相同的内容。

此任一/或规则仅适用于术语位置

只有term position中的支持代码才能使用此DWIM / WAT。 1

一些语句示例显示何时适用:

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

对于本答复的其余部分"支持的代码"表示术语位置中的支撑代码。

听起来很复杂的简单答案

如果在语法上看起来像哈希并且不涉及任何声明,那么它是Hash。否则它是Block{}为空Hash{;}为空Block

难以忍受,详尽无遗的答案

% sigil&d;变量或Pair 文字开头的支持代码,否则只是一个列表,并且不涉及任何直接(非嵌套)声明都将构造一个Hash

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

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

否则它是Block

say WHAT         { $bar, %baz }            # (Block)
say WHAT         { |%bar      }            # (Block)
say WHAT         { %@quux     }            # (Block)
say WHAT         { :foo, my $baz, $bar }   # (Block)

签名也是声明。

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

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

某些支持的代码具有隐式签名:

  • 在大括号内使用显式占位符变量(例如$^foo)会为支撑代码提供隐式签名(其中包含$foo参数)。

  • 在括号内使用代词可以使支撑代码成为签名,即使它没有明确的代码也是如此。 $_@_%_是代词。由于{ :a, .foo },即使$_也会隐式使用.foo,因此也很重要。

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

由于它们的显式/隐式签名,以下两行都构造了Block,尽管大括号内的第一个值是Pair字面值:

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

没有隐式或显式签名且只包含零个或多个逗号分隔值的列表的支撑代码,没有未嵌套的声明,可能构造一个{{ 1}}取决于第一个值。

如果第一个值是Hash sigil' d变量或%字面值,则支持的代码构造Pair,否则构建Hash

Block

强制say WHAT { key => $foo, 'a', 'b' } # (Hash) say WHAT { 'a', 'b', key => $foo } # (Block) say WHAT { %foo, 'a', 'b' } # (Hash) say WHAT { Pair.new('key',$foo), # Pair.new is NOT a literal 'a', 'b' } # (Block) Block解释

  • 要写一个空Hash,请写Block。要写一个空{;},请写Hash

  • 要强制使用支撑代码构建{}而不是Block,请在开头写Hash;

  • 要强制使用支持的代码构建{; ... }而不是Hash,请遵循上述规则或写Block而不是%(...)

脚注

1 一个有价值的DWIM必须适用于大多数编码员'大部分时间都支持,其相关的WAT必须为社区所接受。 (当DWIM没有做到他们的意思时,WAT指的是开发者的惊喜。对于每个DWIM,都有一个或多个WAT。)

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