动态创建 class 具有调用约束
Dynamically created class with invocant constraint
官方docs说class可以像这样动态构建:
constant A := Metamodel::ClassHOW.new_type( name => 'A' );
A.^add_method('x', my method x(A:D:) { say 42 });
A.^compose;
A.new.x(); # x will be only called on instances
但是如果我正在构建一个 class 并且不将其分配给常量而是将其存储在 var 中怎么办(例如当我需要创建一堆 classes在循环中)像这样:
my $x = Metamodel::ClassHOW.new_type( name => 'some custom string' );
$x.^add_method('x', my method ($y:) { say $y });
$x.^compose;
但在这种情况下,我可以在 class ($x.x
) 和实例 ($x.new.x
) 上调用方法 x
,尽管我希望它只被调用在实例上。
我试着像这样定义方法:
$x.^add_method('x', my method ($y:D:) { say $y });
但这会产生错误:
Invalid typename 'D' in parameter declaration.
当然我可以检查方法内部值的定义性,但我想要一些编译时保证(我想相信类型检查是在编译时完成的)。
我尝试使用 signatures and parameters 但找不到创建调用参数的方法,但更重要的是我不确定如何将变量中的签名分配给某个方法。
变化:
my $x = ...
至:
my constant x = my $ = ...
完整:
my constant x = my $ = Metamodel::ClassHOW.new_type( name => 'some custom string' );
x.^add_method('x', my method (x:D $y:) { say $y });
x.^compose;
x = Metamodel::ClassHOW.new_type( name => 'another custom string' );
...
I want some compile-time guarantees (I want to believe that type checking is done in compile time).
通过使 constant
的 RHS 成为变量声明,您可以将静态 compile-time 方面与动态 run-time 方面混合。
(顺便说一句,constant
之前的 my
只是我学究气。像您使用的普通 constant
等同于 our constant
,后者不那么严格比 my constant
.)
我注意到 non-instance 的错误消息不同:
Type check failed in binding to parameter '$y';
expected type some custom string cannot be itself
我猜这是因为通常的消息来自 Mu
或 Any
,而您的 class 没有继承它们中的任何一个。
I am not sure how to assign signature which I have in a variable to some method.
我将不回答该部分。
我能想到的最好的方法是使用参数角色来帮助生成一个方法,并将类型替换为今天的 Raku 签名,如下所示:
my role Helper[::T] {
method foo(T $inv:) {}
}
my &meth = Helper.^parameterize(Int).^pun.^lookup("foo");
say &meth.signature;
输出(Int $inv: *%_)
。将 Int
替换为您正在构建的类型。
官方docs说class可以像这样动态构建:
constant A := Metamodel::ClassHOW.new_type( name => 'A' );
A.^add_method('x', my method x(A:D:) { say 42 });
A.^compose;
A.new.x(); # x will be only called on instances
但是如果我正在构建一个 class 并且不将其分配给常量而是将其存储在 var 中怎么办(例如当我需要创建一堆 classes在循环中)像这样:
my $x = Metamodel::ClassHOW.new_type( name => 'some custom string' );
$x.^add_method('x', my method ($y:) { say $y });
$x.^compose;
但在这种情况下,我可以在 class ($x.x
) 和实例 ($x.new.x
) 上调用方法 x
,尽管我希望它只被调用在实例上。
我试着像这样定义方法:
$x.^add_method('x', my method ($y:D:) { say $y });
但这会产生错误:
Invalid typename 'D' in parameter declaration.
当然我可以检查方法内部值的定义性,但我想要一些编译时保证(我想相信类型检查是在编译时完成的)。
我尝试使用 signatures and parameters 但找不到创建调用参数的方法,但更重要的是我不确定如何将变量中的签名分配给某个方法。
变化:
my $x = ...
至:
my constant x = my $ = ...
完整:
my constant x = my $ = Metamodel::ClassHOW.new_type( name => 'some custom string' );
x.^add_method('x', my method (x:D $y:) { say $y });
x.^compose;
x = Metamodel::ClassHOW.new_type( name => 'another custom string' );
...
I want some compile-time guarantees (I want to believe that type checking is done in compile time).
通过使 constant
的 RHS 成为变量声明,您可以将静态 compile-time 方面与动态 run-time 方面混合。
(顺便说一句,constant
之前的 my
只是我学究气。像您使用的普通 constant
等同于 our constant
,后者不那么严格比 my constant
.)
我注意到 non-instance 的错误消息不同:
Type check failed in binding to parameter '$y';
expected type some custom string cannot be itself
我猜这是因为通常的消息来自 Mu
或 Any
,而您的 class 没有继承它们中的任何一个。
I am not sure how to assign signature which I have in a variable to some method.
我将不回答该部分。
我能想到的最好的方法是使用参数角色来帮助生成一个方法,并将类型替换为今天的 Raku 签名,如下所示:
my role Helper[::T] {
method foo(T $inv:) {}
}
my &meth = Helper.^parameterize(Int).^pun.^lookup("foo");
say &meth.signature;
输出(Int $inv: *%_)
。将 Int
替换为您正在构建的类型。