class Attribute { }

在 Raku 术语中,属性是指每个实例/对象存储槽。Attribute 用于在元级别讨论类和角色的属性。

正常使用属性不需要用户显式使用此类。

特征§

特征是默认的§

分配了Nil的属性将恢复为使用特征is default设置的默认值。对于数组或关联数组,is default的参数将设置默认项值或哈希值。

class C {
    has $.a is default(42is rw = 666
}
my $c = C.new;
say $c;
$c.a = Nil;
say $c;
# OUTPUT: «C.new(a => 666)␤C.new(a => 42)␤» 
class Foo {
    has @.bar is default(42is rw
};
my $foo = Foo.newbar => <a b c> );
$foo.bar =Nil;
say $foo# OUTPUT: «Foo.new(bar => [42])␤»

特征是必需的§

multi trait_mod:<is> (Attribute $attr:$required!)

特征is required将标记属性,以便在实例化对象时用值填充它。如果不这样做,将导致运行时错误。

class C {
    has $.a is required
}
my $c = C.new;
CATCH{ default { say .^name''.Str } }
# OUTPUT: «X::Attribute::Required: The attribute '$!a' is required, but you did not provide a value for it.␤»

此特征还允许使用具有:D笑脸的类型对属性进行类型化,而无需为其提供默认值

class Power {
    has Numeric:D $.base     is required;
    has Numeric:D $.exponent is required;
    multi method Numeric(::?CLASS:D: --> Numeric:D{
        $!base ** $!exponent
    }
}

从 6.d 语言版本开始可用(早期实现存在于 Rakudo 编译器 2018.08+ 中):您可以指定属性必需的原因

class D {
    has $.a is required("it is a good idea");
}
my $d = D.new;
CATCH{ default { say .^name''.Str } }
# OUTPUT: «X::Attribute::Required: The attribute '$!a' is required because it is a good idea,␤but you did not provide a value for it.␤» 

is required不仅影响默认构造函数,它还检查较低级别的属性,因此它将适用于使用bless编写的自定义构造函数。

特征已弃用§

multi trait_mod:<is>(Attribute:D $r:$DEPRECATED!)

将属性标记为已弃用,可以选择使用消息来代替。

class C {
    has $.foo is DEPRECATED("'bar'");
}
my $c = C.newfoo => 42 );  # doesn't trigger with initialization (yet) 
say $c.foo;                  # does trigger on usage

程序完成后,这将在 STDERR 上显示类似这样的内容

# Saw 1 occurrence of deprecated code. 
# ===================================== 
# Method foo (from C) seen at: 
# script.raku, line 5 
# Please use 'bar' instead.

特征是可读写的§

multi trait_mod:<is> (Attribute:D $attr:$rw!)

将属性标记为可读写,而不是默认的readonly。属性的默认访问器将返回可写值。

class Boo {
   has $.bar is rw;
   has $.baz;
};
 
my $boo = Boo.new;
$boo.bar = 42# works 
$boo.baz = 42;
CATCH { default { put .^name''.Str } };
# OUTPUT: «X::Assignment::RO: Cannot modify an immutable Any␤»

特征已构建§

multi trait_mod:<is>(Attribute:D $a:$built!)

默认情况下,此特性允许通过 .new 在对象构造期间设置一个私有属性。通过传递布尔值 False,可以使用相同的特性来阻止通过 .new 设置公有属性

class Foo {
    has $!bar is built# same as `is built(True)` 
    has $.baz is built(False);
 
    method bar {
        $!bar
    }
}
 
my $foo = Foo.new(bar => 1baz => 2);
say $foo.bar# OUTPUT: «1␤» 
say $foo.baz# OUTPUT: «Any␤»

在 Rakudo 编译器的 2020.01 版本中可用。

方法§

获取 Attribute 类型对象的通常方法是内省

class Useless {
    has @!things;
}
my $a = Useless.^attributes(:local)[0];
say $a.raku;            # OUTPUT: «Attribute.new␤» 
say $a.name;            # OUTPUT: «@!things␤» 
say $a.package;         # OUTPUT: «(Useless)␤» 
say $a.has_accessor;    # OUTPUT: «False␤»

通常无法从外部修改私有属性,但由于 Attribute 处于元类的级别,所以一切都公平公正。

方法名称§

method name(Attribute:D: --> Str:D)

返回属性的名称。请注意,这始终是私有名称,因此如果将属性声明为 has $.a,则返回的名称为 $!a

class Foo {
    has @!bar;
}
my $a = Foo.^attributes(:local)[0];
say $a.name;            # OUTPUT: «@!bar␤»

方法包§

method package()

返回此属性所属的包(类/语法/角色)。

class Boo {
    has @!baz;
}
my $a = Boo.^attributes(:local)[0];
say $a.package;         # OUTPUT: «(Boo)␤»

方法 has_accessor§

method has_accessor(Attribute:D: --> Bool:D)

如果属性具有公有访问器方法,则返回 True

class Container {
    has $!private;
    has $.public;
}
my $private = Container.^attributes(:local)[0];
my $public = Container.^attributes(:local)[1];
say $private.has_accessor# OUTPUT: «False␤» 
say $public.has_accessor;  # OUTPUT: «True␤»

方法 rw§

method rw(Attribute:D: --> Bool:D)

对于应用了“is rw”特性的属性,返回 True

class Library {
    has $.address# Read-only value 
    has @.new-books is rw;
}
my $addr = Library.^attributes(:local)[0];
my $new-books = Library.^attributes(:local)[1];
say $addr.rw;      # OUTPUT: «False␤» 
say $new-books.rw# OUTPUT: «True␤»

方法 readonly§

method readonly(Attribute:D: --> Bool:D)

对于只读属性(这是默认值)返回 True,或者对于标记为 is rw 的属性返回 False

class Library {
    has $.address# Read-only value 
    has @.new-books is rw;
}
my $addr = Library.^attributes(:local)[0];
my $new-books = Library.^attributes(:local)[1];
say $addr.readonly;      # OUTPUT: «True␤» 
say $new-books.readonly# OUTPUT: «False␤»

方法 required§

method required(Attribute:D: --> Any:D)

对于应用了“is required”特性的属性,返回 1,或者如果属性没有应用该特性,则返回 Mu。如果“is required”特性应用于一个字符串,则会返回该字符串而不是 1

class Library {
    has $.address is required;
    has @.new-books is required("we always need more books");
}
my $addr = Library.^attributes(:local)[0];
my $new-books = Library.^attributes(:local)[1];
say $addr.required;      # OUTPUT: «1␤» 
say $new-books.readonly# OUTPUT: «"we always need more books"␤»

方法类型§

method type(Attribute:D: --> Mu)

返回属性的类型约束。

class TypeHouse {
    has Int @.array;
    has $!scalar;
    has @.mystery;
}
my @types = TypeHouse.^attributes(:local)[0..2];
for 0..2 { say @types[$_].type }
# OUTPUT: «(Positional[Int]) 
# (Mu) 
# (Positional)␤»

方法 get_value§

method get_value(Mu $obj)

返回存储在对象 $obj 的此属性中的值。

class Violated {
    has $!private-thing = 5;
}
my $private = Violated.^attributes(:local)[0];
say $private.get_value(Violated.new); # OUTPUT: «5␤»

请注意,此方法违反了对象的封装,应谨慎使用。此地有龙。

方法 set_value§

method set_value(Mu $objMu \new_val)

将值 new_val 绑定到对象 $obj 的此属性。

class A {
    has $!a = 5;
    method speak() { say $!a}
}
my $attr = A.^attributes(:local)[0];
my $a = A.new;
$a.speak# OUTPUT: «5␤» 
$attr.set_value($a42);
$a.speak# OUTPUT: «42␤»

请注意,此方法违反了对象的封装,应谨慎使用。此地有龙。

方法 gist§

multi method gist(Attribute:D:)

返回类型名称后跟属性名称。

class Hero {
    has @!inventory;
    has Str $.name;
    submethod BUILD:$name:@inventory ) {
        $!name = $name;
        @!inventory = @inventory
    }
}
say Hero.^attributes(:local)[0]; # OUTPUT: «Positional @!inventory␤» 

由于 say 隐式调用 .gist,因此这里会产生输出。

可选内省§

已弃用§

如果某个属性标记为 DEPRECATED,则可以调用 DEPRECATED 方法,它将返回 "something else"(如果未指定具体原因)或使用 DEPRECATED 特征指定的字符串。

如果某个属性标记为 DEPRECATED,则不能调用 DEPRECATED 方法。因此,应使用 .?method 语法。

class Hangout {
    has $.table;
    has $.bar is DEPRECATED("the patio");
}
my $attr-table = Hangout.^attributes(:local)[0];
my $attr-bar = Hangout.^attributes(:local)[1];
with $attr-table.?DEPRECATED -> $text {     # does not trigger 
    say "Table is deprecated with '$text'";
    # OUTPUT: 
}
with $attr-bar.?DEPRECATED -> $text {
    say "Bar is deprecated with '$text'";
    # OUTPUT: «Bar is deprecated with 'the patio'"␤» 
}

Typegraph§

Attribute 的类型关系
raku-type-graph Attribute Attribute Any Any Attribute->Any Mu Mu Any->Mu

展开上面的图表