如何根据多个变量的定义编写条件?

How can you write a conditional based on the definedness of multiple variables?

我时常发现自己需要用两个或三个分支编写条件语句:至少,一个用于定义所有两个或多个变量,另一个用于定义其中任何一个或 none定义。有时最后一个分支需要是两个独立的分支。有哪些简短而有趣的写法?

withwithoutorwith 是与 ifunlesselsif 类似的条件句,除了它们检查他们论点的定义而不是他们的真实性。当与这些结合使用时,结点会变成线程,因此可以这样写这样的条件:

my Str $foo = '' if 2.rand.floor;
my Str $bar = '' if 2.rand.floor;
with $foo & $bar {
    say 'yes';
} orwith $foo | $bar {
    say 'maybe';
} else {
    say 'no';
}

或者对于任意数量的变量:

my Str @strings = do 2.rand.floor ?? '' !! Nil for ^3;
with all @strings {
    say 'yes';
} orwith any @strings {
    say 'maybe';
} else {
    say 'no';
}

with 等人很棒,我可能会写一个链式 with 语句,特别是如果特定变量组合的匹配是临时的,或者我认为在考虑到代码。

但是考虑到你的字面问题,以及你在回答中的场景,我更有可能选择 given/when

my ($foo, $bar, $baz) = (Mu, 42).pick xx Inf;

given $foo, $bar, $baz {
  when .all.defined { say 'yes'   }
  when .any.defined { say 'maybe' }
  default           { say 'no'    }
}

您可以创建一个组合值并将签名用作 when 条件。

:(…) 是签名文字的语法。)

given ($foo,$bar,$baz) {
   when :( Any:D, Any:D, Any:D ) { 'all defined' }
   when :( Any:D, Any:D, Any:U ) { '$baz undefined' }
   when :( Any:D, Any:_, Any:D ) { '$bar not checked' }

   default { … }
}

您可以创建词法常量以使其更短。

my constant D = Any:D; # defined
my constant U = Any:U; # undefined
my constant _ = Any:_; # either

given ($foo,$bar,$baz) {
   when :(D,D,D) { 'all defined' }
   when :(D,D,U) { '$baz undefined' }
   when :(D,_,D) { '$bar not checked' }

   default { … }
}

或者如果你想让它更直观:

my constant term:<▣> = Any:D; # defined
my constant term:<□> = Any:U; # undefined
my constant term:<▨> = Any:_; # either

given ($foo,$bar,$baz) {
   when :(▣,▣,▣) { 'all defined' }
   when :(▣,▣,□) { '$baz undefined' }
   when :(▣,▨,▣) { '$bar not checked' }

   default { … }
}

您可以创建一个子程序来提供要使用的签名。

## something like this should work
## but something is weird with the returns constraint
#sub prefix:<d> ( $_ ) {
#  my constant %lookup = (
#    '▣' => Parameter.new( type => Any:D ),
#    '□' => Parameter.new( type => Any:U ),
#    '▨' => Parameter.new( type => Any:_ ),
#  );
#  Signature.new: params => %lookup{.comb}
#}

sub prefix:<d> ( $_ ) {
  my constant %lookup = (
    '▣' => 'Any:D',
    '□' => 'Any:U',
    '▨' => 'Any:_',
  );
  use MONKEY-SEE-NO-EVAL;
  EVAL ":(%lookup{.comb}.join(","))"
}

given ($foo,$bar,$baz) {
   when d'▣▣▣' { 'all defined' }
   when d'▣▣□' { '$baz undefined' }
   when d'▣▨▣' { '$bar not checked' }

   default { … }
}