Perl 6 中的 bless

bless 方法


method bless(*%attrinit) returns Mu:D

相比 new方法來說更低層級(jí)別的對(duì)象構(gòu)造方法。

創(chuàng)建一個(gè)和調(diào)用者同類型的新對(duì)象, 使用具名參數(shù)來初始化屬性, 并返回創(chuàng)建后的對(duì)象。

在自定義構(gòu)造函數(shù)時(shí)可以使用該方法:

class Point {
    has $.x;
    has $.y;

    # multi 是可選的
    multi method new($x, $y) {
        self.bless(:$x, :$y);
    }
}

# 重寫構(gòu)造函數(shù)后, 不需要傳具名參數(shù)了
my $p = Point.new(-1, 1);
say $p.x; # -1

雖然你可以自定義構(gòu)造函數(shù), 記得它會(huì)讓子類繼承變得更困難。

use v6;

# bless 的原理
class Dog {
    has $.name;
    my $.counter; # 類方法
    # 重寫 new 方法, 使用位置參數(shù)創(chuàng)建實(shí)例
    method new ($newName) {
        $.counter++;
        self.bless(name => $newName);
    }
}

my $dog = Dog.new("yayaya");
say $dog.name;   # yayaya
say Dog.counter; # 1

讓我們創(chuàng)建一個(gè)對(duì)象


在 Perl 6 中創(chuàng)建一個(gè)對(duì)象相當(dāng)容易。 作為類的作者你真的不必關(guān)心(至少在最簡單的情況下), 你從 Mu 類繼承了一個(gè)默認(rèn)的構(gòu)造函數(shù)。作為類的使用者, 你僅僅寫出 MyClass.new(attrib1 => $value1) 就能創(chuàng)建一個(gè) MyClass類的對(duì)象, 同時(shí)初始化了一個(gè)公開的屬性 attrib1。

運(yùn)行初始化代碼


如果你想在對(duì)象創(chuàng)建中運(yùn)行某些初始化代碼, 那么你一點(diǎn)兒也沒有必要?jiǎng)佑?new方法。使用 BUILD 子方法:

class C {
    submethod BUILD {
        say "創(chuàng)建一個(gè) C 的實(shí)例";
    }
}

C.new();  # 創(chuàng)建一個(gè) C 的實(shí)例

BUILD submethod 由構(gòu)造函數(shù)自動(dòng)調(diào)用, 并且可以處理任何必要的初始化。BUILD submethod 也能接收用戶傳遞給 new() 方法的具名參數(shù)。

(以防你疑惑, submethod不能被子類繼承的方法。)

因?yàn)?BUILD 運(yùn)行在尚未完全構(gòu)建好的對(duì)象上, 屬性只有在被聲明為具名參數(shù)的時(shí)候才可以被訪問:

submethod BUILD(:$!attr1, :$!attr2) {
    # 這兒可以使用 $!attr1 和 $!attr2
}

該語法也自動(dòng)的使用和 new方法同名的具名參數(shù)的值初始化屬性 。

use v6;

class Cat {
    has $.fullname;
    has $.nickname;

    submethod BUILD(:$!fullname, :$!nickname) {
        say "造了一只貓, 它的全名是 $!fullname, 它的昵稱是 $!nickname";
    }
}

# 造了一只貓, 它的全名是 Camelia, 它的昵稱是 Rakudo Star
Cat.new(fullname => 'Camelia', nickname => 'Rakudo Star');

所以下面的兩個(gè)類聲明, 表現(xiàn)一樣:

class D {
    has $.x;
}
# and
class D {
    has $!x;                   # 私有屬性
    submethod BUILD(:$!x) {}   # 允許 D.new( x => $x )
    method x() {$!x}           # accessor
}

這也解釋了 has $.x 等價(jià)于 has $!x 加上 accessor 的原理。

自定義構(gòu)造函數(shù)


假如你對(duì)具名參數(shù)不感冒, 而你想自定義一個(gè)接收一個(gè)強(qiáng)制位置參數(shù)的構(gòu)造函數(shù)。那樣你就需要自定義 new方法。要?jiǎng)?chuàng)建一個(gè)對(duì)象, 被重寫的 new 方法中必須調(diào)用 self.bless

class C {
    has $.size;
    method new($x) {
        self.bless(*, size => 2 * $x);
    }
}

say C.new(3).size; # 接收一個(gè)位置參數(shù), 打印出 6

bless的第一個(gè)參數(shù) *****號(hào)告訴它創(chuàng)建一個(gè)空對(duì)象自身。

如果你想開啟額外的具名參數(shù), 那很容易:

class C {
    has $.size;
    method new($x, *%remaining) {
        self.bless(*, size => 2 * $x, |%remaining);
    }
}

注意, 這兩個(gè)概念(自定義 new() 和 BUILD() (sub)methods) 是正交的; 你一次可以使用它倆, 它倆能和諧共處。

屬性的默認(rèn)值


為屬性提供默認(rèn)值的最方便的方式是在聲明屬性的時(shí)候?yàn)閷傩蕴峁┠J(rèn)值:

class Window {
    has $.height = 600;
    has $.width  = $.height * 1.618;
    ...
}

默認(rèn)值只會(huì)用在底層屬性沒有被 newBUILD接觸的時(shí)候使用。

理解對(duì)象初始化


假如你有一個(gè)類 C 繼承自類 B, 那么創(chuàng)建一個(gè)類 C 的對(duì)象的處理看起來是這樣:

img

用戶調(diào)用 C.new, 這反過來調(diào)用 self.bless(*, |args)。bless 方法創(chuàng)建了一個(gè)新的存儲(chǔ)新創(chuàng)建對(duì)象的 P6Opaque 對(duì)象。這就是調(diào)用上圖中的 CREATE

分配完存儲(chǔ)空間和屬性初始化之后, new把控制權(quán)傳給BUILDALL(順帶傳遞所有的具名參數(shù)), 這反過來會(huì)從層級(jí)樹的頂端開始, 調(diào)用繼承層級(jí)樹上所有類的 BUILD 方法, 最后調(diào)用類 C 的 BUILD 方法。

這樣的設(shè)計(jì)允許你花費(fèi)最少的力氣來替換初始化的一部分, 尤其是自定義 newBUILD 方法會(huì)很容易寫。

use v6;

class B {
    has $.name;

    submethod BUILD(:$!name) {
        say "調(diào)用了 B 的 BUILD, 我叫 $!name"
    }
}

class C is B {
    has $.nickname;

    submethod BUILD(:$!nickname, :$name) {
        say "調(diào)用了 C 的 BUILD, 我叫 $!nickname, 我爸爸是 $name"
    }
    method new(:$nickname) {
        self.bless(nickname => 'Camelia', name => 'Lucy');
    }
}

my $c = C.new(nickname => 'HANMEIMEI');

打?。?/p>

調(diào)用了 B 的 BUILD, 我叫 Lucy
調(diào)用了 C 的 BUILD, 我叫 Camelia, 我爸爸是 Lucy
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,545評(píng)論 19 139
  • 國家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報(bào)批稿:20170802 前言: 排版 ...
    庭說閱讀 12,365評(píng)論 6 13
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,652評(píng)論 18 399
  • Object Orientation in Perl 6 Perl 6 有很多預(yù)先定義好的類型,這些類型可以歸為 ...
    焉知非魚閱讀 521評(píng)論 0 1
  • 遠(yuǎn)方響起蒼茫的馬蹄 我在湖邊等你 等你為我披上衣 湖面陣陣漣漪 是你走過留下的的足跡 你如白蓮花 自水中升起 問候...
    柳曉生閱讀 199評(píng)論 0 2

友情鏈接更多精彩內(nèi)容