跳轉到內容

Raku 程式設計/類和屬性

來自 Wikibooks,開放書籍,開放世界

類和物件

[編輯 | 編輯原始碼]

到目前為止,我們已經看到了面向過程程式設計的構建塊:表示式、分支、迴圈和子例程的列表,它們告訴計算機該做什麼以及如何做。Raku 很好的支援面向過程程式設計,但這並不是 Raku 支援的唯一程式設計風格。Raku 很好的適應的另一個常見正規化是面向物件方法。

物件是資料及其操作的組合。物件的“資料”稱為其屬性,物件的“操作”稱為其方法。從這個意義上說,屬性定義了物件的“狀態”,而方法定義了物件的“行為”。

類是建立物件的模板。當提到特定類的物件時,通常將該物件稱為該類的例項。

類使用 class 關鍵字定義,並被賦予一個名稱

class MyClass {

}

在類宣告內部,您可以定義屬性、方法或子方法。

屬性使用 has 關鍵字定義,並使用特殊的語法指定。例如,考慮以下類

class Point3D {
    has $!x-axis;
    has $!y-axis;
    has $!z-axis;
}

Point2D 類定義了 3D 座標系中的一個點,它有三個屬性,分別名為 x-軸、y-軸和 z-軸。

在 Raku 中,所有屬性都是私有的,一種明確表達這一點的方式是使用 ! twigil。使用 ! twigil 宣告的屬性只能在類內部透過使用 !attribute-name 直接訪問。用這種方式宣告屬性的另一個重要後果是,物件不能使用預設的 new 建構函式進行填充。

如果您使用 . twigil 而不是 ! twigil 宣告屬性,則會自動生成一個只讀訪問器[檢查拼寫] 方法。您可以將 . twigil 視為“屬性 + 訪問器”。這個訪問器,它是一個以其屬性命名的“方法”,可以從類外部呼叫並返回其屬性的值。為了允許透過提供的訪問器更改屬性,必須將 is rw 特性新增到屬性中。

之前的 Point3D 類可以宣告如下

class Point3D {
    has $.x-axis;
    has $.y-axis;
    has $.z-axis is rw;
}

鑑於 . twigil 聲明瞭一個 ! twigil 和一個訪問器[檢查拼寫] 方法,即使屬性使用 . twigil 宣告,也可以始終使用 ! twigil 使用它們。

方法的定義與普通子例程相同,只是有一些關鍵區別

  1. 方法使用 method 關鍵字而不是 sub
  2. 方法具有特殊的變數 self,它引用正在呼叫方法的物件。這被稱為呼叫者
  3. 方法可以直接訪問物件的內部特性。

在定義方法時,您可以為呼叫者指定不同的名稱,而不是必須使用 self。為此,您將其放在方法簽名的開頭,並用冒號將其與簽名的其餘部分隔開

method myMethod($invocant: $x, $y)

在此上下文中,冒號被視為一種特殊的逗號型別,因此您可以用額外的空格來寫它,如果這樣更容易

method myMethod($invocant  :  $x, $y)

以下是一個示例

class Point3D {
    has $.x-axis;
    has $.y-axis;
    has $.z-axis;
    
    method set-coord($new-x, $new-y, $new-z) {
        $!x-axis = $new-x;
        $!y-axis = $new-y;
        $!z-axis = $new-z;
    }
    
    method print-point {
        say "("~$!x-axis~","~$!y-axis~","~$!z-axis~")";
    }
    
    # method using the self invocant
    method distance-to-center {
        return sqrt(self.x-axis ** 2 + self.y-axis ** 2);
    }
    
    # method using a custom invocant named $rect
    method polar-coordinates($rect:) {
        my $r = $rect.distance-to-center;
        my $theta = atan2($rect.y-axis, $rect.x-axis);
        return "("~$r~","~$theta~","~$rect.z-axis~")";
    }
}

物件是其型別為給定類的“資料項”。物件包含類定義的任何屬性,並且還可以訪問類中的任何方法。物件使用 new 關鍵字建立。

使用 Point3D 類

my $point01 = Point3D.new();

類建構函式new() 可以接受命名方法,這些方法用於初始化類的任何屬性

# Either syntax would work for object initialization
my $point01 = Point3D.new(:x-axis(3), :y-axis(4), :z-axis(6));
my $point02 = Point3D.new(x-axis => 3, y-axis => 4, z-axis => 6);

類中的方法使用點符號呼叫。這是物件、一個句點,然後是該方法的名稱。

$point01.print-point();
say $point01.polar-coordinates();

當沒有為點符號方法呼叫提供物件時,將使用預設變數 $_ 代替

$_ = Point3D.new(:x-axis(6), :y-axis(8), :z-axis(6));;
.print-point();
say .polar-coordinates();

基本類系統使“資料”及其操作該資料的“程式碼例程”能夠以邏輯的方式捆綁在一起。但是,大多數類系統還有更高階的功能,這些功能也允許繼承,這使得類能夠相互構建。繼承是類形成邏輯層次結構的能力。Raku 支援類的正常繼承和子類,但也支援稱為mixin角色的特殊高階功能。我們將不得不為後面的章節保留其中一些更難的功能,但我們將在本章中介紹一些基礎知識。

基本型別

[編輯 | 編輯原始碼]

我們在前面的章節中討論了 Perl 的一些基本型別。您可能會驚訝地發現,所有 Raku 資料型別都是類,並且所有這些值都具有可以使用的內建方法。在這裡,我們將討論一些可以對到目前為止看到的各種物件呼叫的方法。

.print.say

[編輯 | 編輯原始碼]

我們已經看到了內建函式 printsay。所有內建類都有相同名稱的方法,這些方法列印物件的字串形式。

.perleval

[編輯 | 編輯原始碼]

我們將快速討論一下 eval 函式。eval 使我們能夠在執行時編譯並執行 Raku 程式碼字串。

eval("say 'hello world!';");

所有 Raku 物件都具有一個名為 .perl 的方法,該方法返回表示該物件的 Raku 程式碼字串。

my Int $x = 5;
$x.perl.say;          # "5"

my @y = (1, 2, 3);
@y.perl.say;          # "[1, 2, 3]"

my %z = :first(1), :second(2), :third(3);
%z.perl.say;          # "{:first(1), :second(2), :third(3)}"

上下文和強制轉換方法

[編輯 | 編輯原始碼]

有一些方法可以顯式地將給定的資料項更改為不同的形式。這就像一種強制給定的資料項以不同的上下文進行解釋的顯式方法。以下是一個部分列表

.item
返回標量上下文的專案。
.iterator
返回物件的迭代器。我們將在後面的章節中討論迭代器。
.hash
返回雜湊上下文的物件
.list
返回陣列或“列表”上下文的物件
.Bool
返回物件的布林值
.陣列
返回包含物件資料的陣列
.雜湊
返回包含物件資料的雜湊
.迭代器
返回物件的迭代器。我們將在後面的章節中討論迭代器。
.標量
返回指向物件的標量引用
.字串
返回物件的字串表示

內省方法

[編輯 | 編輯原始碼]
.WHENCE
返回物件型別自動建立閉包的程式碼引用。我們稍後將討論自動建立和閉包。
.WHERE
返回資料物件的記憶體位置地址
.WHICH
返回物件的標識值,對於大多數物件來說,它就是它的記憶體位置(即它的 .WHERE)
.HOW
(HOW = 高階工作方式) 返回處理此物件的元類
.WHAT
返回當前物件的型別物件
下一頁: 註釋和 POD | 上一頁: 程式碼塊和閉包
主頁: Raku 程式設計
華夏公益教科書