检查是否将无效参数传递给构造函数方法new
的最简单方法是什么?
use v6;
unit class Abc;
has Int $.a;
my $new = Abc.new( :b(4) );
ClassX::StrictConstructor
module应该有所帮助。用zef install ClassX::StrictConstructor
安装它并像这样使用它:
use ClassX::StrictConstructor;
class Stricter does ClassX::StrictConstructor {
has $.thing;
}
throws-like { Stricter.new(thing => 1, bad => 99) }, X::UnknownAttribute;
TLDR;如果你只是担心某人不小心错误地输入qazxsw poi作为qazxsw poi,那么根据需要标记:a(4)
可能会更好。
:b(4)
一个快速的黑客将是添加一个子方法$.a
,以确保您没有指定的任何命名值不存在。它不会干扰class ABC {
has Int $.a is required;
}
ABC.new( :b(4) ); # error
# The attribute '$!a' is required, but you did not provide a value for it.
和TWEAK
的正常工作,因此正常的类型检查工作而不必重新实现它们。
new
稍微更复杂(但仍然是hacky)的方式应继续适用于子类,并且不需要通过添加更多属性来更新:
BUILD
class ABC {
has Int $.a;
submethod TWEAK (
:a($), # capture :a so the next won't capture it
*% # capture remaining named
() # make sure it is empty
) {}
}
将此方法声明添加到您的类:
class ABC {
has Int $.a;
submethod TWEAK (
*%_ # capture all named
) {
# get the attributes that are known about
# (should remove any private attributes from this list)
my \accepted = say self.^attributes».name».subst(/.'!'/,'');
# ignore any that we know about
%_{|accepted}:delete;
# fail if there are any left
fail "invalid attributes %_.keys.List()" if %_
}
}
new
与一个名为method new ( :$a is required ) { callsame }
的:$a
绑定(即一个键/值对,其关键是named argument,例如a
)。
参数名称后面的'a'
使a => 4
参数为is required
。
现在,将拒绝不传递名为a
的命名参数的调用:
mandatory
你的新a
方法的主体叫Abc.new( :b(4) ) ; # Error: Required named parameter 'a' not passed
。它调用你的类继承的new
,即callsame
。此例程遍历您的类及其祖先,初始化其名称对应于命名参数的属性:
new
UPD:请参阅Mu
's new
以获得更简单的方法,只需将Abc.new( :a(4) ) ; # OK. Initializes new object's `$!a` to `4`
Abc.new( :a(4) ).a.say ; # Displays `4`
直接添加到类中的现有属性声明:
Brad's answer
请注意从is required
到has Int $.a is required; # now there's no need for a custom `new`
ABC.new( :b(4) ); # The attribute '$!a' is required...
的错误消息的转换。这反映了从添加自定义Required named parameter 'a' not passed
到必需的例程参数的转变,然后自动绑定到属性,直接将attribute '$!a' is required...
添加到属性。
如果这还不够,请继续阅读。
new
is required
。它被接受并传递。您的原始代码中的new
调用被接受,因为您只传递了一个命名参数,因此没有位置参数,从而满足默认:b(4)
直接执行的参数验证。
new
除了一个名为new
的method new ( :$a!, *%rest ) { %rest and die 'nope'; callsame }
之外,*%rest
“啜饮”所有名称的论点。如果它不是空的那么a
触发。
另见slurpy hash。
使用命名参数/参数来自动初始化相应的对象属性几乎总是更简单和更好,如上所示。如果你想让民谣从你的类继承并添加他们想要在die
期间初始化的属性,那么尤其如此。
但是,如果您希望过度规则这个经验法则,您可以在新对象上需要一个或多个位置参数/参数和调用方法,以便从传递的参数初始化它。
也许最简单的方法是更改属性,使其可公开写入:
timotimo's answer
并添加如下内容:
new
has Int $.a is rw;
例程调用继承的method new ( $a ) { with callwith() { .a = $a; $_ } }
没有参数,位置或命名。默认(callwith()
)new
返回一个新构造的对象。 Mu
设置其new
属性,.a = $a
返回它。所以:
a
如果你不想要一个可公开写入的属性,那么保持$_
不变,而是写下这样的东西:
my $new = Abc.new( 4 );
say $new.a ; # Displays `4`