美思 [Raku] 程式設計教學:多型 (Polymorphism)

Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Email

Duck type

Duck type 是動態型別語言的一種特性,duck type 物件不需在意其實際的類別,僅需在意該類別是否有提供相對應的公開方法。如以下實例:

class Duck {
    method speak {
        "Pack pack".say;
    }
}

class Dog {
    method speak {
        "Wow wow".say;
    }
}

class Tiger {
    method speak {
        "Halum halum".say;
    }
}

my @animals = (
        Duck.new,
        Dog.new,
        Tiger.new,
    );

for @animals -> $a {
    $a.speak;
}

在這個例子中,只要 @animals 陣列中的物件有實作 speak 方法即可,我們不需要去檢查各個物件實際的類別。

對於從靜態型別語言轉換過來的程式設計者,時常有檢查物件所屬的類別的衝動;然而,過度地檢查型別,便失去使用動態型別語言的優點。如果想確保型別安全,建議使用 role 來約束類別的行為,如同我們前文所舉的例子。

子類型

子類型 (subtyping) 也是一種實作多型的方法,可以透過繼承或 roles 來實作。由於 Perl 6 是動態型別語言,本身已經支援 duck typing,不太需要使用子類型實作多型。如果想實作子類型,建議使用 role。

函式重載

使用 multi 可以宣告同名但不同參數的函式或方法。我們在先前的範例中已經展示過其用法。

運算子重載

透過運算子重載,衍生類別也可以像內建類別般,使用運算子來操作類別;運算子重載常用在數學相關的類別,像是向量 (vector) 或矩陣 (matrix) 等。以下實例實作向量加法:

role IVector {
    method elems { ... }
    method at($i) { ... }
}

class Vector does IVector {
    has Numeric @!vec;

    submethod BUILD(:array(@a)) {
        @!vec = @a;
    }

    method elems {
        @!vec.elems;
    }

    method at($i) {
        return @!vec[$i];
    }
}

# Overloading indexing method.
multi sub postcircumfix:<[ ]>(IVector $v, $i) {
    $v.at($i);
}

# Overloading addition method.
multi sub infix:<+>(IVector $p, IVector $q) {
    if $p.elems != $q.elems {
        die "Unequal vector length";
    }

    my @out;

    loop (my $i = 0; $i < $p.elems; $i++) {
        @out.push($p[$i] + $q[$i])    
    }

    Vector.new(array => @out);
}

my $p = Vector.new(array => (1, 2, 3));
my $q = Vector.new(array => (2, 3, 4));
my $v = $p + $q;
$v[0] == 3 or die "Wrong value";
$v[1] == 5 or die "Wrong value";
$v[2] == 7 or die "Wrong value";

某種程度來說,運算子重載偏向使用者自訂的語法糖,而非必備的語法特性。有許多現代語言支援運算子重載,但也有語言不支援,像是 Java 和 Go。Perl 6 的運算子重載相當靈活,甚至可以自訂新的運算子;但筆者對於自訂運算子的態度較為保守,過度地使用運算子重載,反而會造成代碼難以閱讀。

泛型

由於 Perl 6 是動態型別語言,不太需要使用泛型程式,即可將相同程式碼套用在不同型別上。Perl 6 的 paramaterized role 提供有限度的泛型程式支援,但不若其他語言的泛型系統來得完整,官方對此也著墨甚少,故此處不深入介紹。

關於作者

身為資訊領域碩士,美思認為開發應用程式的目的是為社會帶來價值。如果在這個過程中該軟體能成為永續經營的項目,那就是開發者和使用者雙贏的局面。

美思喜歡用開源技術來解決各式各樣的問題,但必要時對專有技術也不排斥。閒暇之餘,美思將所學寫成文章,放在這個網站上和大家分享。