內容

名稱

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,以取得初始化範例。

範例

範例 1

讓結構元素具有也是結構的類別類型,這就是結構的巢狀方式。在此,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);
範例 2

可以重新定義存取函式,以提供額外的值檢查等。在此,我們希望 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!
範例 3

可以將 元素=> 成對清單傳遞給已產生類別的建構函式,以初始化結構。如果未為特定元素指定初始化,則會執行其預設初始化。不存在元素的初始化會被靜默忽略。

請注意,巢狀類別的初始化可以指定為該類別的物件,或指定為初始化雜湊的參考,該雜湊會傳遞給巢狀結構的建構函式。

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.