内容

名称

perlclass - Perl 类语法参考

概要

use v5.38;
use feature 'class';

class My::Example 1.234 {
    field $x;

    ADJUST {
        $x = "Hello, world";
    }

    method print_message {
        say $x;
    }
}

My::Example->new->print_message;

描述

本文档描述了 Perl 的 class 特性的语法,该特性提供了支持面向对象编程范式的原生关键字。

历史

从 Perl 5 开始,对对象的支持围绕着使用包名对引用进行“祝福”的概念。这样的引用可以用来调用它被祝福的包(或其任何父包)中的子例程。这个系统虽然简单,但足够灵活,可以允许创建多个更高级的、由社区驱动的面向对象系统。

类特性是类语法核心实现,与其他编程语言中的类语法类似。它不是一个 `bless` 包装器,而是一个完全内置于 Perl 解释器的新系统。

关键字

启用 `class` 特性允许在当前包的范围内使用以下新关键字

class

class NAME BLOCK

class NAME VERSION BLOCK

class NAME;

class NAME VERSION;

`class` 关键字声明一个新的包,该包旨在成为一个类。所有其他来自 `class` 特性的关键字都应该在这个声明的范围内使用。

class WithVersion 1.000 {
    # class definition goes here
}

类可以在块或语句语法中声明。如果使用块,则块的主体包含类的实现。如果使用语句形式,则文件中的其余部分将被使用,直到下一个 `class` 或 `package` 语句。

`class` 和 `package` 声明类似,但类会自动获得一个名为 `new` 的构造函数 - 你不需要(也不应该)编写它。此外,在类块中,你可以声明字段和方法。

field

field VARIABLE_NAME;

field VARIABLE_NAME = EXPR;

field VARIABLE_NAME : ATTRIBUTES;

field VARIABLE_NAME : ATTRIBUTES = EXPR;

字段是在类范围内可见的变量 - 更具体地说,在 "method" 和 `ADJUST` 块中。每个类实例都有自己的字段存储,彼此独立。

字段的行为类似于普通的词法作用域变量。它有一个 sigil,并且对类私有(尽管创建访问器方法将使其从外部访问)。主要区别在于不同的实例在同一个作用域中访问不同的值。

class WithFields {
    field $scalar = 42;
    field @array  = qw(this is just an array);
    field %hash   = (species => 'Martian', planet => 'Mars');
}

字段可以选择具有初始化表达式。如果存在,表达式将在每个对象实例的构造函数中进行评估。在每次评估期间,表达式可以使用任何先前设置的字段的值,以及查看作用域中的任何其他变量。

class WithACounter {
    my $next_count = 1;
    field $count = $next_count++;
}

当与 `:param` 字段属性结合使用时,默认表达式可以使用任何 `=`、`//=` 或 `||=` 运算符。使用 `=` 的表达式将在调用者根本没有向构造函数传递相应参数时应用。使用 `//=` 的表达式也将在调用者传递了参数但值为未定义时应用,而使用 `||=` 的表达式将在值为 false 时应用。

method

method METHOD_NAME SIGNATURE BLOCK

method METHOD_NAME BLOCK

method SIGNATURE BLOCK

method BLOCK

方法是旨在在类对象上下文中调用的子例程。

一个名为 `$self` 的变量将自动在 `method` 的词法作用域中创建,该变量填充了当前对象实例。

方法始终表现得好像use feature 'signatures'生效一样,但就签名而言,$self不会出现在参数列表中。

class WithMethods {
    field $greetings;

    ADJUST {
        $greetings = "Hello";
    }

    method greet($name = "someone") {
        say "$greetings, $name";
    }
}

就像常规子程序一样,方法可以是匿名的

class AnonMethodFactory {

    method get_anon_method {
        return method {
            return 'this is an anonymous method';
        };
    }
}

属性

上面提到的关键字的具体方面是使用属性来管理的。所有属性都以冒号开头,并且可以在项目名称之后附加一个或多个属性,用空格分隔。

类属性

:isa

类可以通过使用:isa类属性从一个超类继承。

class Example::Base { ... }

class Example::Subclass :isa(Example::Base) { ... }

继承的方法是可见的,可以被调用。字段始终是词法变量,因此不能通过继承访问。

:isa属性可以请求基类的最小版本;它的应用类似于use - 如果提供的版本过低,它将在编译时失败。

class Example::Subclass :isa(Example::Base 2.345) { ... }

如果:isa属性尚未加载,它将尝试require指定的模块。

字段属性

:param

具有:param属性的标量字段将从传递给构造函数的命名参数中获取其值。默认情况下,参数将与字段具有相同的名称(减去其开头的$符号),但可以在属性中指定不同的名称。

field $x :param;
field $y :param(the_y_value);

如果没有默认表达式,则构造函数需要该参数;调用者必须传递它,否则将抛出异常。使用默认表达式,它将变为可选。

方法属性

还没有。

对象生命周期

构造

每个对象都以构造函数调用开始其生命周期。构造函数始终命名为new,并且像对类名进行方法调用一样被调用

my $object = My::Class->new(%arguments);

在构造过程中,类字段将与%arguments哈希进行比较,并在可能的情况下进行填充。

调整

可以在构造过程中执行对象调整以运行用户定义的代码。这是借助ADJUST块完成的,这些块按声明顺序调用。

它们类似于BEGIN块,这些块在包编译期间运行。但是,它们还可以访问$self词法变量(对象实例)和在此之前创建的所有对象字段。

生命周期

在构建阶段完成后,对象就可以使用了。

使用 blessedScalar::Util::blessedbuiltin::blessed)在对象上将返回类的名称,而 reftypeScalar::Util::reftypebuiltin::reftype)将返回字符串 'OBJECT'

销毁

就像其他引用一样,当对象引用计数达到零时,它将自动被销毁。

待办事项

此功能仍处于实验阶段,并且非常不完整。以下列表概述了仍需添加或更改的工作类型。

作者

Paul Evans

Bartosz Jarzyna