我正在从Perl5学习Perl6.
我正在查看副词:exists https://docs.perl6.org/type/Hash#:exists但是没有:defined副词
但我很担心,因为perl5 exists与&之间有区别defined:存在和定义之间有什么区别?
我怎样才能在Perl6中做这样的事情?
if (defined $hash{key}) {
$hash{key}++;
} else {
$hash{key} = 1;
}
Run Code Online (Sandbox Code Playgroud)
if defined %hash{'key'} {
%hash{'key'}++;
} else {
%hash{'key'} = 1;
}
Run Code Online (Sandbox Code Playgroud)
使用defined例程或方法.见5to6-perlfunc - 定义
defined 是一个值的属性。
exists 是散列索引操作的变体选择器。
这在 Perl5 和 Perl6 中都是正确的。
只是他们处理的方式不同而已。
假设你有一个这样的哈希:
my %h = ( a => 1, b => 2, c => Int );
Run Code Online (Sandbox Code Playgroud)
它有三个键:
say %h.keys; # (a b c)
Run Code Online (Sandbox Code Playgroud)
您可以获取与键关联的值:
my $value = %h{'a'};
Run Code Online (Sandbox Code Playgroud)
你可以询问价值是否是 defined
say defined $value; # True
Run Code Online (Sandbox Code Playgroud)
现在让我们尝试一下c:
my $value = %h{'c'};
say defined $value; # False
Run Code Online (Sandbox Code Playgroud)
并与D:
my $value = %h{'D'};
say defined $value; # False
Run Code Online (Sandbox Code Playgroud)
请注意,即使D不是散列中的键,您返回的值看起来与查找相同c。
价值不知道你是如何得到它的。它对哈希索引操作一无所知。
即使您不将其存储在变量中,它也是一样的。
say defined %h{'c'}; # False
say defined %h{'D'}; # False
Run Code Online (Sandbox Code Playgroud)
所以我们必须告诉索引操作而不是给我们这些信息。
my $exists = %h{'D'}:exists;
say $exists; # False
Run Code Online (Sandbox Code Playgroud)
此外,如果您将结果%h{'D'}用作容器,它[神奇地] 开始存在。
say %h{'D'}:exists; # False
say %h{'D'}.perl; # Any
say %h{'D'}:exists; # False
%h{'D'}++;
say %h{'D'}:exists; # True
say %h{'D'}; # 1
Run Code Online (Sandbox Code Playgroud)
那么为什么它与 Perl5 不同呢?
在 Perl5 中exists和defined是关键字。在 Perl6 中它们不是。
它们在 Perl6 中没有任何特别之处、形状或形式。
这是用于检查的 Perl5 版本exists:
use v5.12.0;
use warnings;
my %h = ( a => 1, b => 2, c => undef );
my $exists = exists $h{D};
say $exists ? 'True' : 'False'; # False
Run Code Online (Sandbox Code Playgroud)
如果您调用编译器,-MO=Concise您将获得它将执行的操作码列表。
这只是显示这exists是一个操作码的部分:
…
d <;> nextstate(main 5 -e:1) v:%,us,*,&,{,$,fea=2 ->e
g <2> sassign vKS/2 ->h # <----- =
- <1> ex-exists sK/1 ->f # <-\
e <+> multideref($h{"D"}) sK/EXISTS ->f # <--+-- exists $h{D}
- <0> ex-padhv sR ->e # <-/
f <0> padsv[$exists:5,6] sRM*/LVINTRO ->g # <----- $exists
h <;> nextstate(main 6 -e:1) v:%,us,*,&,{,$,fea=2 ->i
…
Run Code Online (Sandbox Code Playgroud)
在multideref($h{"D"})标有EXISTS,且有ex-exists操作码。
的列表defined非常相似。
Perl6 的设计目标之一是尽可能减少特殊情况。这就是为什么既不exists或者defined是关键字。
如果您查找definedRakudo 代码库中的位置,您会发现:
proto sub defined(Mu, *%) is pure {*}
multi sub defined(Mu \x) { x.defined }
Run Code Online (Sandbox Code Playgroud)
defined只是一个接受一个值的子例程,并调用该.defined值的方法。
由于它执行方法调用,因此该值可以决定是否认为已定义。
所有值继承的默认值都在Mu.defined source 中:
proto method defined(|) {*}
multi method defined(Mu:U: --> False) { }
multi method defined(Mu:D: --> True) { }
Run Code Online (Sandbox Code Playgroud)
所以默认是类型对象未定义,实例被定义。
一个值得注意的例外是Failure对象:
multi method defined(Failure:D: --> False) { $!handled = 1 }
Run Code Online (Sandbox Code Playgroud)
因此,这使得 Failure 对象的实例被视为未定义。它也将导致故障认为自己已处理。
(如果没有处理失败,它会在垃圾收集时发出警告。)
那么:exists上%h{'D'}呢?
在 Perl6 中,“普通”运算符被定义为具有特殊名称的子程序。
sub foo (%hash, $key){}
say &foo.signature.perl;
# :(%hash, $key)
say &postcircumfix:<{ }>.signature.perl;
# :($, $?, Mu $?, *%)
Run Code Online (Sandbox Code Playgroud)
请注意,postcircumfix 运算符{ }由多个多子支持,但我们实际上只需要查看其中一个。
multi sub postcircumfix:<{ }>( \SELF, \key, Bool() :$exists!, *%other ) is raw {
SLICE_ONE_HASH( SELF, key, 'exists', $exists, %other )
}
Run Code Online (Sandbox Code Playgroud)
你可以忽略大部分。要注意的关键是:$exists!。
默认情况下,命名参数是可选的,并且没有选择多的说法。为了:exists强制选择该选项,必须将其标记为“required” !。
每当您看到时,:exists您都可以将其视为:exists(True)and 的缩写exists => True。
(也是and 的:$exists缩写。):exists($exists)exists => $exists
所以这两行在功能上是相同的:
my $exists = %h{'D'}:exists;
my $exists = postcircumfix:<{ }> %h, 'D', exists => True;
Run Code Online (Sandbox Code Playgroud)
它告诉操作员(子程序)使用exists变体。
请注意,它还传递了 的值$exists,这意味着它可以进行反向存在检查。
say %h{'c'}:exists; # True
say %h{'c'}:!exists; # False
say %h{'D'}:exists; # False
say %h{'D'}:!exists; # True
Run Code Online (Sandbox Code Playgroud)
:!exists是:exists(False)and 的缩写exists => False。
所以没有:definedpostcircumfix 变化的原因{ }是不需要有一个。只需询问结果值是否已定义。