【问题标题】:Determine if a variable in Raku is set确定是否设置了 Raku 中的变量
【发布时间】:2020-05-19 06:55:50
【问题描述】:

我有意避免使用 defined 一词,因为变量很可能具有已定义的值,但 .defined 方法将返回 false(例如,失败)。

有什么方法可以判断一个变量是否已经设置了值?

my $foo;
say $foo; # (Any), its type object, no value assigned
my Str $bar;
say $bar; # (Str), its type object, no value assigned
my $abc = Str;
say $abc; # (Str), the type object we assigned to $abc

我们如何区分$bar(未设置值,键入为Str)与$abc(值设置为Str)?

鉴于$bar.WHICH == $abc.WHICH,但$bar.VAR.WHICH !== $abc.VAR.WHICH,以及.defined 之类的方法都将返回false,是否有任何快速简便的方法来确定是否存在设定值?

我想它可以根据默认值进行检查,但是没有办法区分值是通过未设置还是在代码中设置。

【问题讨论】:

    标签: raku


    【解决方案1】:

    变量总是被设置为某种值。

    如果您不将其设置为某个值,则会为您选择一个值。
    具体来说,它将被设置为默认值。
    (如果你不选择默认值,它将被设置为类型对象。)

    my $abc;
    
    say $abc.VAR.default.raku;
    # Any
    
    my Int $def = 42;
    
    say $def.VAR.default.raku;
    # Int
    
    my $ghi is default(42) = 2;
    
    say $ghi.VAR.default.raku;
    # 42
    

    你所要求的并不是 Raku 真正支持的东西。

    不过,您可能会伪造一些接近的东西。
    Mu.new 的每个实例都是唯一的。)

    sub is-not-set ( Mu $_ is raw ) {
      $_.self =:= $_.VAR.default
    }
    
    my $abc is default(Mu.new);
    my $def is default(Mu.new) = Any;
    my $ghi is default(Mu.new) = Mu.new;
    
    say is-not-set $abc; # True
    say is-not-set $def; # False
    say is-not-set $ghi; # False
    

    问题是分配Nil 也会将其设置为默认值。

    $def = Nil;
    say is-not-set $def; # True
    

    将查找默认值并分配它。

    $ghi = $ghi.VAR.default;
    say is-not-set $ghi; # True
    

    我认为你不应该担心这些事情。

    如果您真的需要在第一次分配给变量时发生某些事情,您可以执行以下操作:

    my $abc := Proxy.new(
      # this FETCH only needs to return the default
      # as this Proxy gets replaced upon the first assignment
      FETCH => -> $ { Any },
    
      STORE => -> $, $value {
        # replace the Proxy with a new Scalar
        $abc := do { my $abc = $value };
    
        say 'first assignment just happened'
      },
    );
    
    say $abc;
    # Any
    
    $abc = 1;
    # first assignment just happened
    
    say $abc;
    # 1
    
    $abc = 2;
    
    say $abc;
    # 2
    

    do 块就在那里,所以$abc.VAR.name 返回$abc
    否则你可以写$abc := my $ = $value

    【讨论】:

    • 好吧,“总是设置为某个值”可能是stackoverflow.com/questions/61818213/… 中的 OP 的一些混淆之处,并且使 jnthn 对为什么 (Type:U) 不那么好的推理填写 gist 方法。我想知道是否有办法在文档中解决这个问题以明确这一点
    【解决方案2】:

    我认为这两个值是相同的,但容器有不同的type constraints

    试试

    my Str $foo;
    my  $bar = Str;
    
    use Test;
    
    cmp-ok $bar, &[===], $foo, 'The values are identical';
    isa-ok $bar, Str;
    isa-ok $foo, Str;
    isa-ok $bar.VAR.of, Mu;
    nok $bar.VAR.of.isa(Str), 'The container $bar is not of Str' ;
    isa-ok $foo.VAR.of, Str;
    
    done-testing();
    
    ok 1 - The values are identical
    ok 2 - The object is-a 'Str'
    ok 3 - The object is-a 'Str'
    ok 4 - The object is-a 'Mu'
    ok 5 - The container $bar is not of Str
    ok 6 - The object is-a 'Str'
    1..6
    

    【讨论】:

      【解决方案3】:

      这是一般问题还是实施问题?如果是后者,也许(ab)使用角色是一种选择?

      role isUnset {}; 
      my Str $a = Str but isUnset; 
      say $a ~~ isUnset; 
      
      # meanwile
      $a = 'set'; 
      # ...
      $a = Str;
      
      # and then
      say $a ~~ isUnset; # Now False
      

      【讨论】:

      • 我根本不考虑这种滥用行为。 role 的一个重要(并且迄今为止很少使用)角色是作为一个 mixin,具有很大的限制,即 mixin 可能无法在接收 mixin 的对象的突变中幸存下来,而这反过来又是重要的角色之一(因此很少使用)mixin 的作用是附加元数据。如果角色被混合到类型对象中,那么如果对象发生变异,则保证会丢失 mixin。在我看来,这似乎是对roles 的完美使用,它为 OP 提供了一个完美的简单解决方案。
      【解决方案4】:

      my Str $barmy $bar = Str 的结果相同,都是 Str 类型,但没有确定的值。 Str 是一个类型对象,而不是一个值。

      如果您给$bar 一个确定的值,例如"Str".defined 将返回True(注意裸词周围的引号)。

      【讨论】:

      • “导致同样的事情”:但并非如此。 my Str $bar; $bar = 3 错误,因为$bar 被键入为Str,但my $bar = Str; $bar = 3 没有,因为$bar 没有被键入
      【解决方案5】:

      您可以尝试为变量分配默认值,而不是保持未定义:

       my Str $bar is default("");
      

      $bar 将是 Str 仅当它被分配了该值类型;如果通过分配 Nil 删除了它的值,它将再次默认为空字符串。事实上,变量的默认值是它的类型对象,所以:

      my Str $foo;
      my $bar = Str;
      say $foo eqv $bar
      

      实际上会返回 True。

      【讨论】:

      • 对,那么我们如何确定我们是否获得了默认值或是否已为其分配了默认值?还是那不可能?
      • @user0721090601 我不这么认为。
      猜你喜欢
      • 2014-09-15
      • 2013-09-06
      • 1970-01-01
      • 2015-03-14
      • 1970-01-01
      • 1970-01-01
      • 2020-04-07
      • 1970-01-01
      • 2016-11-12
      相关资源
      最近更新 更多