Class::Struct - 将类 struct 类似的数据类型声明为 Perl 类
use Class::Struct;
# declare struct, based on array:
struct( CLASS_NAME => [ ELEMENT_NAME => ELEMENT_TYPE, ... ]);
# declare struct, based on hash:
struct( CLASS_NAME => { ELEMENT_NAME => ELEMENT_TYPE, ... });
package CLASS_NAME;
use Class::Struct;
# declare struct, based on array, implicit class name:
struct( ELEMENT_NAME => ELEMENT_TYPE, ... );
# Declare struct at compile time
use Class::Struct CLASS_NAME => [ELEMENT_NAME => ELEMENT_TYPE, ...];
use Class::Struct CLASS_NAME => {ELEMENT_NAME => ELEMENT_TYPE, ...};
# declare struct at compile time, based on array, implicit
# class name:
package CLASS_NAME;
use Class::Struct ELEMENT_NAME => ELEMENT_TYPE, ... ;
package Myobj;
use Class::Struct;
# declare struct with four types of elements:
struct( s => '$', a => '@', h => '%', c => 'My_Other_Class' );
my $obj = Myobj->new; # constructor
# scalar type accessor:
my $element_value = $obj->s; # element value
$obj->s('new value'); # assign to element
# array type accessor:
my $ary_ref = $obj->a; # reference to whole array
my $ary_element_value = $obj->a(2); # array element value
$obj->a(2, 'new value'); # assign to array element
# hash type accessor:
my $hash_ref = $obj->h; # reference to whole hash
my $hash_element_value = $obj->h('x'); # hash element value
$obj->h('x', 'new value'); # assign to hash element
# class type accessor:
my $element_value = $obj->c; # object reference
$obj->c->method(...); # call method of object
$obj->c(new My_Other_Class); # assign a new object
Class::Struct
导出一个函数,struct
。给定元素名称和类型列表,以及可选的类名称,struct
创建一个实现“类 struct 类似”数据结构的 Perl 5 类。
新类获得一个构造函数方法 new
,用于创建 struct 对象。
struct 数据中的每个元素都有一个访问器方法,用于分配给元素并获取其值。可以通过在包中声明同名 sub
来覆盖默认访问器。(请参阅示例 2。)
每个元素的类型可以是标量、数组、哈希或类。
struct()
函数struct
函数有三种形式的参数列表。
struct( CLASS_NAME => [ ELEMENT_LIST ]);
struct( CLASS_NAME => { ELEMENT_LIST });
struct( ELEMENT_LIST );
第一种和第二种形式明确指明了要创建的类的名称。第三种形式假定当前包名称为类名称。
由第一种和第三种形式创建的类的对象基于数组,而由第二种形式创建的类的对象基于哈希。基于数组的形式会快一些且更小;基于哈希的形式更灵活。
由 struct
创建的类不能是除 UNIVERSAL
以外的另一个类的子类。
但是,它可以用作其他类的超类。为了方便这一点,生成的构造方法使用双参数祝福。此外,如果该类基于哈希,则每个元素的键都以类名称为前缀(请参阅《Perl Cookbook》,第 13.12 条)。
在由 struct
创建的类中,不得明确定义名为 new
的函数。
ELEMENT_LIST 的形式为
NAME => TYPE, ...
每个名称-类型对声明结构的一个元素。每个元素名称都将定义为访问器方法,除非明确定义了该名称的方法;在后一种情况下,如果设置了警告标志 (-w),则会发出警告。
Class::Struct
可以在编译时创建你的类。这样做的主要原因显而易见,因此你的类就像 Perl 中的任何其他类一样。在编译时创建你的类会使事件顺序类似于使用任何其他类(或 Perl 模块)。
编译时类创建和运行时类创建之间没有显着的速度提升,只是一种新的、更标准的事件顺序。
四种元素类型——标量、数组、哈希和类——由字符串表示——'$'
、'@'
、'%'
和类名称——前面可以加上 '*'
。
struct
为元素提供的访问器方法取决于元素的声明类型。
'$'
或 '*$'
)元素是标量,默认初始化为 undef
(但请参阅 "使用 new 初始化")。
访问器的参数(如果有)被分配给元素。
如果元素类型是 '$'
,则返回元素的值(在分配之后)。如果元素类型是 '*$'
,则返回对元素的引用。
'@'
或 '*@'
)元素是一个数组,默认初始化为 ()
。
如果没有参数,访问器将返回对元素的整个数组的引用(无论元素是否指定为 '@'
或 '*@'
)。
如果有一个或两个参数,第一个参数是一个指定数组中一个元素的索引;第二个参数(如果存在)将分配给数组元素。如果元素类型为 '@'
,访问器将返回数组元素值。如果元素类型为 '*@'
,则返回对数组元素的引用。
作为一个特例,当访问器以数组引用作为唯一参数调用时,这将导致对整个数组元素进行赋值。将返回对象引用。
'%'
或 '*%'
)元素是一个哈希,默认初始化为 ()
。
如果没有参数,访问器将返回对元素的整个哈希的引用(无论元素是否指定为 '%'
或 '*%'
)。
如果有一个或两个参数,第一个参数是一个指定哈希中一个元素的键;第二个参数(如果存在)将分配给哈希元素。如果元素类型为 '%'
,访问器将返回哈希元素值。如果元素类型为 '*%'
,则返回对哈希元素的引用。
作为一个特例,当访问器以哈希引用作为唯一参数调用时,这将导致对整个哈希元素进行赋值。将返回对象引用。
'Class_Name'
或 '*Class_Name'
)元素的值必须是对命名类或其子类进行祝福的引用。该元素默认情况下未初始化。
访问器的参数(如果有)将分配给元素。如果这不是一个适当的对象引用,访问器将 croak
。
如果元素类型不以 '*'
开头,访问器将返回元素值(在赋值之后)。如果元素类型以 '*'
开头,则返回对元素本身的引用。
new
初始化struct
始终创建一个名为 new
的构造函数。该构造函数可以获取一个初始化器列表,用于新结构的各个元素。
每个初始化器都是一对值:元素名称 =>
值。标量元素的初始化器值只是一个标量值。数组元素的初始化器是一个数组引用。哈希的初始化器是一个哈希引用。
类元素的初始化器是对应类的对象,或其子类的对象,或对哈希的引用,其中包含要传递给元素构造函数的命名参数。
有关初始化的示例,请参见下面的示例 3。
为结构元素提供也是结构的类类型是嵌套结构的方式。此处,Timeval
表示时间(秒和微秒),Rusage
有两个元素,每个元素的类型均为 Timeval
。
use Class::Struct;
struct( Rusage => {
ru_utime => 'Timeval', # user time used
ru_stime => 'Timeval', # system time used
});
struct( Timeval => [
tv_secs => '$', # seconds
tv_usecs => '$', # microseconds
]);
# create an object:
my $t = Rusage->new(ru_utime=>Timeval->new(),
ru_stime=>Timeval->new());
# $t->ru_utime and $t->ru_stime are objects of type Timeval.
# set $t->ru_utime to 100.0 sec and $t->ru_stime to 5.0 sec.
$t->ru_utime->tv_secs(100);
$t->ru_utime->tv_usecs(0);
$t->ru_stime->tv_secs(5);
$t->ru_stime->tv_usecs(0);
可以重新定义访问器函数,以提供对值等的附加检查。此处,我们希望 count
元素始终为非负,因此我们相应地重新定义 count
访问器。
package MyObj;
use Class::Struct;
# declare the struct
struct ( 'MyObj', { count => '$', stuff => '%' } );
# override the default accessor method for 'count'
sub count {
my $self = shift;
if ( @_ ) {
die 'count must be nonnegative' if $_[0] < 0;
$self->{'MyObj::count'} = shift;
warn "Too many args to count" if @_;
}
return $self->{'MyObj::count'};
}
package main;
$x = new MyObj;
print "\$x->count(5) = ", $x->count(5), "\n";
# prints '$x->count(5) = 5'
print "\$x->count = ", $x->count, "\n";
# prints '$x->count = 5'
print "\$x->count(-5) = ", $x->count(-5), "\n";
# dies due to negative argument!
可以向生成类的构造函数传递 element=>value 对的列表,用以初始化结构。如果未为特定元素指定初始化器,则会执行其默认初始化。不存在的元素的初始化器将被静默忽略。
请注意,嵌套类的初始化器可以指定为该类的对象,或指定为对哈希的引用,其中包含传递给嵌套结构的构造函数的初始化器。
use Class::Struct;
struct Breed =>
{
name => '$',
cross => '$',
};
struct Cat =>
[
name => '$',
kittens => '@',
markings => '%',
breed => 'Breed',
];
my $cat = Cat->new( name => 'Socks',
kittens => ['Monica', 'Kenneth'],
markings => { socks=>1, blaze=>"white" },
breed => Breed->new(name=>'short-hair', cross=>1),
or: breed => {name=>'short-hair', cross=>1},
);
print "Once a cat called ", $cat->name, "\n";
print "(which was a ", $cat->breed->name, ")\n";
print "had 2 kittens: ", join(' and ', @{$cat->kittens}), "\n";
Damian Conway 于 2001-09-10 修改,v0.62。
Modified implicit construction of nested objects.
Now will also take an object ref instead of requiring a hash ref.
Also default initializes nested object attributes to undef, rather
than calling object constructor without args
Original over-helpfulness was fraught with problems:
* the class's constructor might not be called 'new'
* the class might not have a hash-like-arguments constructor
* the class might not have a no-argument constructor
* "recursive" data structures didn't work well:
package Person;
struct { mother => 'Person', father => 'Person'};
Casey West 于 2000-11-08 修改,v0.59。
Added the ability for compile time class creation.
Damian Conway 于 1999-03-05 修改,v0.58。
Added handling of hash-like arg list to class ctor.
Changed to two-argument blessing in ctor to support
derivation from created classes.
Added classname prefixes to keys in hash-based classes
(refer to "Perl Cookbook", Recipe 13.12 for rationale).
Corrected behaviour of accessors for '*@' and '*%' struct
elements. Package now implements documented behaviour when
returning a reference to an entire hash or array element.
Previously these were returned as a reference to a reference
to the element.
Jim Miner 于 1997-04-02 重命名为 Class::Struct
并修改。
members() function removed.
Documentation corrected and extended.
Use of struct() in a subclass prohibited.
User definition of accessor allowed.
Treatment of '*' in element types corrected.
Treatment of classes as element types corrected.
Class name to struct() made optional.
Diagnostic checks added.
最初由 Dean Roehrich 编写,名为 Class::Template
。
# Template.pm --- struct/member template builder
# 12mar95
# Dean Roehrich
#
# changes/bugs fixed since 28nov94 version:
# - podified
# changes/bugs fixed since 21nov94 version:
# - Fixed examples.
# changes/bugs fixed since 02sep94 version:
# - Moved to Class::Template.
# changes/bugs fixed since 20feb94 version:
# - Updated to be a more proper module.
# - Added "use strict".
# - Bug in build_methods, was using @var when @$var needed.
# - Now using my() rather than local().
#
# Uses perl5 classes to create nested data types.
# This is offered as one implementation of Tom Christiansen's
# "structs.pl" idea.