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 初始化")。
存取器的引數(如果有)會指定給元素。
如果元素類型為 '$'
,會傳回元素的值(指定後)。如果元素類型為 '*$'
,會傳回元素的參考。
'@'
或 '*@'
)元素是陣列,預設初始化為 ()
。
沒有參數時,存取器會傳回一個參照到元素的整個陣列(無論元素是否指定為 '@'
或 '*@'
)。
有一個或兩個參數時,第一個參數是一個索引,指定陣列的一個元素;第二個參數(如果存在)會指定到陣列元素。如果元素類型是 '@'
,存取器會傳回陣列元素值。如果元素類型是 '*@'
,會傳回一個參照到陣列元素。
在特殊情況下,當存取器被呼叫時,只有一個陣列參照作為參數,這會導致整個陣列元素的指定。會傳回物件參照。
'%'
或 '*%'
)元素是一個雜湊,預設初始化為 ()
。
沒有參數時,存取器會傳回一個參照到元素的整個雜湊(無論元素是否指定為 '%'
或 '*%'
)。
有一個或兩個參數時,第一個參數是一個鍵,指定雜湊的一個元素;第二個參數(如果存在)會指定到雜湊元素。如果元素類型是 '%'
,存取器會傳回雜湊元素值。如果元素類型是 '*%'
,會傳回一個參照到雜湊元素。
在特殊情況下,當存取器被呼叫時,只有一個雜湊參照作為參數,這會導致整個雜湊元素的指定。會傳回物件參照。
'類別名稱'
或 '*類別名稱'
)元素的值必須是一個參照,並指定到已命名類別或其子類別。元素預設不會初始化。
存取器的參數(如果存在)會指定到元素。如果這不是一個適當的物件參照,存取器會 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!
可以將 元素=>值 成對清單傳遞給已產生類別的建構函式,以初始化結構。如果未為特定元素指定初始化,則會執行其預設初始化。不存在元素的初始化會被靜默忽略。
請注意,巢狀類別的初始化可以指定為該類別的物件,或指定為初始化雜湊的參考,該雜湊會傳遞給巢狀結構的建構函式。
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.