在 Raku 中,特征 是附加到对象和类的编译器钩子,用于修改其默认行为、功能或表示。作为这样的编译器钩子,它们在编译时定义,尽管它们可以在运行时使用。

使用 trait_mod 关键字,已经定义了几个特征作为语言或 Rakudo 编译器的一部分。接下来将列出并解释它们。

is 特征§

proto trait_mod:<is>(Mu $|{*}

is 应用于任何类型的标量对象,并且可以接受任意数量的命名或位置参数。它是最常用的特征,根据第一个参数的类型,它采用以下形式。

is 应用于类。§

最常见的形式涉及两个类,一个是正在定义的类,另一个是已存在的类,定义了继承关系A is B,如果两者都是类,则定义 A 作为 B 的子类。

is DEPRECATED 可以应用于类、属性或例程,将它们标记为已弃用,并在提供消息时发出消息。

一些 is 的实例被直接翻译成它们所指类的属性:rwnativesizectypeunsignedhiddenarray_type

不可实例化表示特征 与表示本身关系不大,而更多地与特定类可以做什么有关;它实际上阻止了以任何可能的方式创建类的实例。

constant @IMM = <Innie Minnie Moe>;
 
class don't-instantiate is repr('Uninstantiable'{
    my $.counter;
 
    method imm () {
        return @IMM$.counter++ mod @IMM.elems ];
    }
}
say don't-instantiate.imm for ^10;

不可实例化的类仍然可以通过它们的类变量和方法使用,如上所示。但是,尝试以这种方式实例化它们:my $do-instantiate = don't-instantiate.new; 将产生错误 You cannot create an instance of this type (don't-instantiate)

is repr 和原生表示。§

由于 is 特征通常指的是它们所应用的类或对象的性质,因此它们在 原生调用 中被广泛使用,以 指定 将由原生函数通过 is repr 后缀处理的数据结构的表示;同时,is native 用于通过原生函数实际实现的例程。这些是可以使用的表示

  • CStruct 对应于 C 语言中的 struct。它是一个复合数据结构,包含不同且异构的低级数据结构;有关示例和进一步说明,请参见 此处

  • CPPStruct 同样对应于 C++ 中的 struct。但是,目前这仅限于 Rakudo。

  • CPointer 是这些语言中的任何一种的指针。它是一个动态数据结构,必须在使用之前实例化,可以 用于 其方法也是原生的类。

  • CUnion 将使用与 C 中的 union 相同的表示;有关示例,请参见 此处

另一方面,P6opaque 是 Raku 中所有对象使用的默认表示。

class Thar {};
say Thar.REPR;    # OUTPUT: «P6opaque␤»

元对象协议 默认情况下对每个对象和类使用它,除非另有说明;因此,通常情况下,除非您实际上在使用该接口,否则没有必要使用它。

例程上的 is§

is 特征可以在方法和例程的定义中使用,以建立 优先级结合性。它们充当 使用 trait_mod 定义的子例程,它以将要添加的特征的类型和名称作为参数。在子例程的情况下,特征将是一种添加跨越类和角色层次结构的功能的方法,甚至可以用于向独立定义的例程添加行为。

is implementation-detail§

从 Rakudo 编译器的 2020.05 版本开始可用。

此特征由 Raku 语言实现和模块作者使用,用于标记特定例程(包括方法),这些例程不应成为公共 API 的一部分。虽然在直接查找时可以找到这些例程,但它们不会出现在内省结果中

my &do-not-use-routine = CORE::<&DYNAMIC>;
say CORE::.keys.grep(* eq '&DYNAMIC'); # OUTPUT: «()␤»

这些例程不供用户使用,其行为和可用性随时可能发生变化。

从 Rakudo 编译器的 2021.02 版本开始,也可以在类和角色上应用 is implementation-detail 方法。

方法 is-implementation-detail§

method is-implementation-detail(--> True)

应用此特征会使 is-implementation-detail 方法在 Code 上被调用以返回 True,从而向用户暗示如果他们不愿意在未来几年内维护此代码,则不要使用它

my &fail-routine = &fail;
unless &fail-routine.is-implementation-detail {
    say "&fail is not an implementation detail, can expect backward compatibility";
}
 
sub PRIVATE-CALCULATION is implementation-detail { #`(Not safe to rely on this) }
if &PRIVATE-CALCULATION.is-implementation-detail {
    say "You better not to rely on &PRIVATE-CALCULATION unless you really know what you are doing";
}