如何以及如何最好地基于布尔值选择方法/子方法?

Ric*_*rth 9 raku

我在类中有一个方法来返回哈希值,目的是让子类覆盖该方法。但出于测试目的,我想要一个不同的哈希值。当类被实例化时,我希望测试选项被假定为 False,因此:test在不需要时可以省略。

目前我这样做:

class A {
  has %.tmps;
  submethod BUILD( :$test = False ) {
    %!tmps = $test ?? self.test-tmps !! self.default-tmps
  }
  method test-tmps { ... }
  method default-tmps { ... }
}
Run Code Online (Sandbox Code Playgroud)

这就是我想要的,调用my A $x .= newdefault-tmps,并my A $y .=new(:test)调用test-tmps。

但我想知道如何通过多重调度删除 $test 的显式检查。但我无法找出适当的语法。我试过

class A {
  has %.tmps;
  submethod BUILD( :$test = False ) {
    %!tmps = self.get-tmps( :$test )
  }
  multi method get-tmps( :test($)! where * ) {
     # return the hash for test values
  }
  multi method get-tmps( :test($)! where ! * ) {
     # return the hash for default values
  }
}
Run Code Online (Sandbox Code Playgroud)

这不起作用,因为我总是得到测试值,无论我是否:test在 中指定new。所以我的问题是:

  1. 如何仅根据布尔值选择多方法候选者?

  2. 如果我想做的事情是可能的,是否有理由(例如运行时/编译时检查)为什么BUILD由 调用的显式签入会new比多重调度候选选择更好?

然后,如果多重调度有效,那么以下内容是否有效,或者$!test因为其%.tmps构建时间未定义而为 False?

class A {
  has Bool $!test;
  has %.tmps = self.get-tmps( :$!test );
  submethod BUILD( :$!test = False ) {}
  multi method get-tmps( :test($)! where * ) { ... }
 # replacing the following by whatever is the correct syntax
  multi method get-tmps( :test($) where ! * ) { ... }
}
Run Code Online (Sandbox Code Playgroud)

Eli*_*sen 6

首先,现在我更推荐使用TWEAK方法,而不是BUILD方法。TWEAK 语义一般更偏向 DWIM。

TWEAK其次,该方法(或BUILD方法,就此而言)没有什么特别的。所以他们可以multi

这让我想到了以下解决方案:

class A {
    has %.temps;
    multi submethod TWEAK(--> Nil) {
        %!temps = a => 42;
    }
    multi submethod TWEAK(:$test! --> Nil) {
        $test
          ?? (%!temps = a => 666)  # testing
          !! self.TWEAK(|%_);      # NOT testing
    }
}

say A.new(:test).temps;   # {a => 666}
say A.new(:!test).temps;  # {a => 42}
say A.new.temps;          # {a => 42}
Run Code Online (Sandbox Code Playgroud)

请注意!:$test!. 这使得命名参数成为强制性的。test因此,只要指定命名参数,就会选择该候选者。但这也包括用False值指定的情况,如 中所示:!test。这就是为什么需要在该候选人身上进行测试。

另请注意%_中的self.TWEAK(|%_). Raku 中的所有方法都定义了隐式 *%_(slurpy hash)参数。因此,您可以%_在方法内部使用来指示未由显式命名参数捕获的所有参数(例如:$test在本例中)。所以基本上是在没有self.TWEAK(|%_)所有显式命名参数的情况下重新调度。

最后:--> Nil仅仅表明该方法不会返回值。这可能允许编译器生成更有效的字节码。