我想使用字符串匹配将参数限制为MAIN()
。
这有效:
sub MAIN(
Str :$r where * eq any(< aaa bbb ccc >) = "bbb"
) { say $r }
$ perl6 tb.p6 -r="ccc"
ccc
但这不是:
sub MAIN(
Str :$r where * ~~ m:i/< aaa bbb ccc >/ = "bbb",
) { say $r }
$ perl6 ta.p6 -r="ccc"
Use of uninitialized value of type Any in string context.
Methods .^name, .perl, .gist, or .say can be used to stringify it to something meaningful.
in whatevercode at ta.p6 line 2
Usage:
ta.p6 [-r=<Str where { ... }>]
答案 0 :(得分:7)
最大的问题是您同时使用*
和m
来制作WhateverCode lambda。
m/…/
与$_
中发生的任何情况匹配。
这实际上发生在~~
之外。
如果您仅使用m/…/
,那么它将有效
sub MAIN(
Str :$r where m:i/< aaa bbb ccc >/ = "bbb"
) { say $r }
您也可以将:i
放在正则表达式中
/:i < aaa bbb ccc >/
where
子句执行智能匹配,就像~~
进行智能匹配一样。因此像您一样使用两者都是多余的。
在基于智能匹配的功能中,使用$_
运行的表达式被设置为要匹配的值。然后将该表达式的结果与输入进行匹配。
我将使用subset
来尝试更好地解释它
subset Foo of Str where * ~~ m:i/< aaa bbb ccc >/;
当您与之匹配时,首先发生的是Str
检查。
(这相当有效,类型专门化程序也许可以消除此检查)
'ccc' ~~ Str; # Str.ACCEPTS('ccc');
然后,where
子句中的表达式就会在$_
中被检查的值运行。
my $result = do given 'ccc' { * ~~ m:i/< aaa bbb ccc >/ }
# $result holds a closure
接下来发生的是,结果将与要测试的值进行智能匹配。
'ccc' ~~ $result; # $result.ACCEPTS('ccc');
在这种情况下,最后一个将取决于当时$_
中发生的任何事情。
由于这将在语言的深处发生,因此您可能无法控制$_
。
对于where
子句,它可以是任何东西。
$_ = 'fubar';
# v--v
subset Foo where * ~~ m:i/
{ say '$_ = ', $_ }
{ say 'orig = ', $/.orig } # the string that is matched against
< aaa bbb ccc >
/;
my $result = 'ccc' ~~ Foo;
# $_ = fubar
# orig = fubar
say $result;
# False
由于'fubar'
与/< aaa bbb ccc >/
不匹配,结果为False
。
通过添加* ~~
,您还添加了距离怪异的动作。
它不需要* ~~
,因为Regex.ACCEPTS()
不依赖$_
。
$_ = 'fubar';
subset Foo where m:i/
{ say '$_ = ', $_ }
{ say 'orig = ', $/.orig }
< aaa bbb ccc >
/;
my $result = 'ccc' ~~ Foo;
# $_ = fubar
# orig = ccc
say $result
# True
Perl 6之所以执行以下两个级别的代码执行代码是有原因的
subset Bar where $_ eq any < aaa bbb ccc >;
my $result = do given 'ccc' { $_ eq any < aaa bbb ccc > }
# $result = True;
# 'ccc' ~~ $result;
$result.ACCEPTS('ccc');
# $result is True, and True.ACCEPTS() always returns True
请注意,可以将其缩短为:
subset Bar where any < aaa bbb ccc >;
my $result = do given 'ccc' { any < aaa bbb ccc > }
# $result = any < aaa bbb ccc >;
# 'ccc' ~~ $result;
$result.ACCEPTS('ccc');
# any(< aaa bbb ccc >).ACCEPTS('ccc')
所有智能匹配功能都会执行这种双重代码执行。
~~
'ccc' ~~ $_ eq any < aaa bbb ccc > # True.ACCEPTS('ccc')
'ccc' ~~ any < aaa bbb ccc > # any(…).ACCEPTS('ccc')
where
subset Baz where $_ eq any < aaa bbb ccc >
subset Baz where any < aaa bbb ccc >
when
when $_ eq any < aaa bbb ccc > {…}
when any < aaa bbb ccc > {…}
基本上,这是为了使您可以与值,表达式或代码进行智能匹配。
(代码实际上是Perl 6中的一种值)
10 ~~ 0..10; # match against a value
10 ~~ Range.new(0,10); # same as previous line
10 ~~ 0 ≤ * ≤ 10; # match against code
10 ~~ -> $_ { 0 ≤ $_ ≤ 10 } # basically the same as previous line
10 ~~ 0 ≤ $_ ≤ 10; # match against an expression with $_
# (not the same a previous two lines)
我想指出的是Perl 6中的正则表达式是一种函数。
my &foo = sub ($_) {$_ eq 'abc'};
my &bar = * eq 'abc';
my &baz = /^ abc $/;
my &zzz = 'abc' # ERROR
因此* ~~ /…/
正在从已经是函数的事物中创建函数。
它将双重代码执行变成了双重代码执行。
在m/…/
中,m
有效地使正则表达式/函数针对$_
中发生的任何事情运行。
# $_ = Any; # initial value in $_
my &code = * ~~ m/abc/;
my &code = * ~~ ($_ ~~ /abc/); # same as previous line
还有rx
,它与m
相似,只不过它总是返回正则表达式本身而不是调用它的结果。 (光秃的/…/
就像rx/…/
一样)
刚开始时,智能匹配会令人困惑。
我认为这会使Perl 6的专家感到困惑。
(这仍然让我感到困惑,我知道它是如何工作的。)
我在这里尝试解释它的工作也很糟糕,但是我试图与您的问题相关,并且您使用~~
使得解释起来更加困难。
为使自己保持理智,我尝试遵循一些基本规则。
这些适用于~~
,where
和when
。
使用文字或可能的文字。
… ~~ 42
… ~~ 'a'
… ~~ any < aaa bbb ccc >
… ~~ 1..10 # not actually a literal, but literal-like
如果您使用的是表达式,请确保其只能返回True
或False
。
与之匹配的值在$_
中,这对where
的{{1}}子句很有帮助。
subset
如果我刚刚使用过… ~~ 0 < $_
… ~~ $_.lc.contains('abc'); # Returns True or False
when $_.lc.contains('abc') {…}
… where $_.lc.contains('abc');
… ~~ $_.chars.Bool
… ~~ ?$_.chars # prefix:« ? » coerces to Bool
… ~~ ?~$_ # coerce to Str, coerce to Bool
# True if the Str isn't empty
# (so has the same effect as previous two examples)
,则只有在数值与长度相同的情况下它才会匹配。
$_.chars
这就是为什么我建议确保它返回布尔值的原因。
此规则有一个例外。即调用一个例程,该例程返回您要智能匹配的值。
'1' ~~ $_.chars; # True
'3.0' ~~ $_.chars; # True
'1.0' ~~ $_.chars; # False (1.0 == 3)
# that previous one is the same as
do given '1.0' { $_.chars }.ACCEPTS( '1.0' ) # False
# 3.ACCEPTS('1.0')
(这是一个不好的例子,但说明了我的意思。)
使用可通话对象。
这有效地删除了代码执行的第一(表达)层。
(结果值与函数的结果无关。)
… ~~ Date.today.day-of-week;
在其他两个智能匹配功能中都不要使用… ~~ *.lc.contains('abc')
… ~~ {.lc.contains('abc')}
… ~~ /:i abc/ # remember that a regex is a function
when {.lc.contains('abc')} {…}
… where {.lc.contains('abc')};
sub foo ( $_ ) { .lc.contains('abc') }
… ~~ &foo
when &foo {…}
… where &foo;
。
~~
如果有很长的表达,我会对此宽容一些,这只是其中的一部分。
when * ~~ /…/ {…} # don't do this
… where * ~~ /…/ # don't do this either
… where $_ ~~ /…/ # No, … just no.
我从来没有碰到过任何真正有用的代码。
每次我看到when (.chars = 3 ?? $_ ~~ Str !! $_ ~~ Int) {…}
用于智能匹配时,如果没有它,效果会更好。
通过遵守上述规则~~
仍然可以使用,但是出于不同的原因。
m:i/…/
Match实例上的 'ccc' ~~ m:i/ < aaa bbb ccc > /;
my $result = do given 'ccc' { m:i/ < aaa bbb ccc > / }
say $result.perl;
# Match.new(pos => 3, orig => "ccc", hash => Map.new(()), from => 0, list => (), made => Any)
$result = $result.ACCEPTS('ccc');
say $result.perl;
# Match.new(pos => 3, orig => "ccc", hash => Map.new(()), from => 0, list => (), made => Any)
始终返回自身。它也总是真实的。
如果匹配失败,它仍然可以正常工作。 (它返回的是虚假的东西。)
再次遇到.ACCEPTS()
约束和where
条件与when
的右侧相同。
答案 1 :(得分:4)
尝试一下:
sub MAIN(
Str :$r where * ~~ / 'aaa' | 'bbb' | 'ccc' / = "bbb",
) { say $r }
正则表达式中的 < aaa bbb ccc >
未作为数组插入,应按以下方式使用:
my @a = < aaa bbb ccc >;
say so "aaa" ~~ /@a/;