Perl 6:如何检查`new`是否存在无效参数?

问题描述 投票:3回答:3

检查是否将无效参数传递给构造函数方法new的最简单方法是什么?

use v6;
unit class Abc;

has Int $.a;

my $new = Abc.new( :b(4) );
constructor parameter-passing perl6
3个回答
8
投票

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;

6
投票

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

4
投票

Write a custom 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 requiredhas 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...添加到属性。

如果这还不够,请继续阅读。

The default new

  • 接受任何和所有命名参数(对)。然后它将它们传递给在对象构造期间自动调用的其他例程。您在示例代码中传递了命名参数is required。它被接受并传递。
  • 拒绝任何和所有位置参数(不是对)。

您的原始代码中的new调用被接受,因为您只传递了一个命名参数,因此没有位置参数,从而满足默认:b(4)直接执行的参数验证。

Rejecting unknown named arguments (as well as any positional arguments)

new

除了一个名为newmethod new ( :$a!, *%rest ) { %rest and die 'nope'; callsame } 之外,*%rest“啜饮”所有名称的论点。如果它不是空的那么a触发。

另见slurpy hash

Requiring positional arguments instead of named

使用命名参数/参数来自动初始化相应的对象属性几乎总是更简单和更好,如上所示。如果你想让民谣从你的类继承并添加他们想要在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`
© www.soinside.com 2019 - 2024. All rights reserved.