我如何参考新的?

How do I take a reference to new?

假设我有以下代码:

my constant @suits = <Clubs Hearts Spades Diamonds>;
my constant @values = 2..14;

class Card {
    has $.suit;
    has $.value;

    # order is mnemonic of "$value of $suit", i.e. "3 of Clubs"
    multi method new($value, $suit) {
        return self.bless(:$suit, :$value);
    }
}

它定义了一些花色和一些价值,以及成为一张牌的意义。

现在,要构建一副牌,我基本上需要将花色和值的叉积应用于构造函数。

执行此操作的天真的方法当然是使用循环进行迭代:

my @deck = gather for @values X @suits -> ($v, $c) {
    take Card.new($v, $c);
}

但这是 Raku,我们有 a cross function that can take a function as an optional argument!,所以我当然会这样做!

my @deck = cross(@values, @suits, :with(Card.new));
# Unexpected named argument 'with' passed
# in block <unit> at .\example.raku line 36

...等等,不。 这个呢?

my @deck = cross(@values, @suits):with(Card.new);
# Unexpected named argument 'with' passed
# in block <unit> at .\example.raku line 36

仍然没有。也许参考?

my @deck = cross(@values, @suits):with(&Card.new);
# ===SORRY!=== Error while compiling D:\Code\Raku/.\example.raku
# Illegally post-declared type:
#    Card used at line 36

我在某处读到我可以使用 []

将函数转换为中缀运算符
my @deck = cross(@values, @suits):with([Card.new]);
# Unexpected named argument 'with' passed
# in block <unit> at .\example.raku line 36

那也不行。

如果 类 应该只是模块,那么我不应该能够传递函数引用吗?

另外为什么说'with'是出乎意料的?如果我的直觉是正确的,那么它实际上抱怨的是输入的类型,而不是命名参数。

报错信息确实令人费解

:with 参数需要一个 Callable。 Card.new 不是 可调用对象。如果你把它写成 :with( { Card.new($^number, $^suit) } ),它似乎可以工作。

请注意,我没有使用 $^value, $^suit,因为它们按字母顺序排列的顺序不同,因此会以错误的顺序生成值。有关该语法的更多信息,请参阅 The ^ twigil

错误 LTA,this使它稍微好一点。

回到你的问题:你可以找到对应于Card.new^find_method的代码对象。然而,那是行不通的,因为 Card.new 实际上需要 3 个参数:调用者(又名 self)、$value$suit .而 cross 函数只会传递值和花色。

你的问题的标题是“我如何引用新的?”,但这并不是你真正想要做的。

Raku 就是 Raku,你实际上可以参考 new

my $ref = Card.^lookup('new');

虽然你不能随心所欲地使用它。

$ref(2,'Clubs'); # ERROR

问题是方法将 class 或实例作为第一个参数。

$ref(Card, 2,'Clubs');

您可以使用 .assuming 添加它。

$ref .= assuming(Card);
$ref(2,'Clubs');

但这并不比创建块 lambda 好多少

$ref = { Card.new( |@_ ) }
$ref(2,'Clubs');

所有这些工作:

cross( @values, @suits ) :with({Card.new(|@_)})   # adverb outside
cross( @values, @suits,  :with({Card.new(|@_)}) ) # inside at end
cross( :with({Card.new(|@_)}), @values, @suits )  # inside at beginning


@values X[&( {Card.new(|@_)} )] @suits # cross meta-op with fake infix op


do {
    sub new-card ($value,$suit) { Card.new(:$value,:$suit) }
    @values X[&new-card] @suits
}

do {
    sub with ($value,$suit) { Card.new(:$value,:$suit) }
    cross(@values,@suits):&with
}