Desgin Perl 6: S12-Objects

標題


大綱 12: 對象(Objects)

版本


創(chuàng)建于: 2004-08-27

上次修改時間: 2014-8-26

版本:134

概述


這個大綱總結了第12個啟示錄, 它探討關于面向對象的編程订框。

類 (Classes)


S12-class/lexical.t lines 12–61

S12-class/basic.t lines 13–50

S14-roles/lexical.t lines 12–47

類是使用關鍵字 class 聲明的模塊矩桂。 至于模塊, 即公共存儲, 接口, 并且類的名字通過包和它的名字來表示, 這總是(但不必須)一個全局的名字凰萨。 類是一個模塊, 因此能導出東西, 但是類添加了更多的行為來支持 Perl 6 的標準的基于類的 OO百匆。

作為類型對象(type object), 類名代表了它的類型的所有可能值, 因此在計算那種類型的普通對象能做什么時, 類型對象能用作任何屬于該類型的"真實"對象的代理潘拨。 類對象是一個對象, 但是它不是一個類(Class), 因為 Perl 6 中沒有強制性的 Class 類, 還因為在Perl 6 中類型對象被認為是未定義的非迹。 我們想基于類的和基于原型的 OO 編程這兩個都支持惩歉。所以, 所有的元編程是通過當前對象的 HOW 對象來完成的, 這可以把元編程代理給任何它喜歡的元模型上抡谐。 然而, 默認地, 從 Mu 派生的對象支持相當標準的基于類的模型裁奇。

有兩種基本的類聲明語法:

    unit class Foo; # 文件的剩余部分是類的定義
    has $.foo

    class Bar { has $.bar } # block 是類的定義

第一種形式只有當?shù)谝环N聲明是在一個編譯單元(即文件或 EVAL 字符串)中時被允許。

如果類的主體以一個主操作符為單個prefix:<...>(yada)listop 開始的語句, 那么只引入類名而不定義, 并且在同一個作用域中第二次聲明那個類不會抱怨重新定義麦撵。(語句修飾符允許在這樣的 ... 操作符上刽肠。)因此你可以向前聲明你的類:

calss A { ... } # 引入 A 作為類名而不定義
class B { ... } # 引入 B 作為類名而不定義

my A $root .= new(:a(B));

class A {
    has B $.a;
}

class B {
    has A $.b;
}

就像這個例子展示的那樣, 這允許互相遞歸類的定義(但是它不允許遞歸繼承)。

通過 augment 聲明符來擴展類也是可以的, 但是那被認為有點不符合常規(guī)并且不應用于向前聲明免胃。

一個具名的類聲明能作為表達式的一部分出現(xiàn), 就像具名子例程聲明那樣音五。

類主要用于實例管理, 而非代碼復用。 當你只是想提取共有的代碼時考慮使用 roles羔沙。

Perl 6 支持多重繼承, 匿名類和自動裝箱躺涝。

S12-class/anonymous.t lines 5–81

所有的 public 方法調用在 C++ 里就是虛的。

你可能派生自任何內置類型, 但是像Int這樣的低級別派生可能只增加行為, 而不改變表示扼雏。使用構成 and/or 代理來改變表示坚嗜。

因為 Perl 6 中沒有裸字, 裸的類名必須被預先聲明好。你可以預先聲明一個 stub 類并在之后填充它就像你在子例程中的那樣诗充。

S12-class/declaration-order.t lines 14–21

S12-class/stubs.t lines 4–40

你可以使用 :: 前綴來強制一個名字解釋為類名或類型名苍蔬。 在左值上下文中, :: 前綴是一個 no-op, 但是在聲明式的上下文中, 它在聲明的作用域中綁定了一個新的類型名, 伴隨著任何其它通過聲明聲明的東西。

S12-class/literal.t lines 7–25

如果沒有 my 或其它作用域聲明符, 那么一個裸的 class 聲明符聲明了一個 our聲明符, 即一個在當前包中的名字蝴蜓。 因為類文件開始解析于 GLOBAL 包中, 文件中第一個聲明的類把它自己安裝為一個全局的名字, 之后的聲明隨后把它們自己安裝在當前類中而不是全局的包中碟绑。

因此, 要在當前的包(或模塊, 或類)中聲明一個內部的類, 那使用 our class 或僅僅 class。 要聲明一個本地作用域的類, 使用 my class茎匠。 類的名字總是從最內的作用域開始搜索, 直到最外層的作用域格仲。 至于起始的 ::, 類名中出現(xiàn)的 :: 不是暗示全局性(不像 Perl 5)。 所以外層的搜索能查看搜索過的名字空間的孩子汽抚。

內部的 class 或 role 在一般的上下文中必須被本地作用域化, 如果它依賴于任何一般的參數(shù)或類型的話; 并且這樣的內部類或 role 也叫做泛型抓狭。

類的特性(Class traits)


類的特性使用 is 來設置:

    class MyStruct is rw { ... }

單繼承


isa 也僅僅是一個特性, 碰巧是另一個類:

    class Dog is Mammal { ... }

多重繼承


多重繼承使用多個 is 來指定:

class Dog is Mammal is Pet { ... }
?```    
#### 合成
Roles 使用 `does` 代替 `is`:
?```perl
class Dog is Mammal does Pet { ... }

also 聲明符


你也可以使用 also 聲明符把這些都放在里面:

class Dog {
    also is Mammal;
    also does Pet;
}

(然而, also 聲明符主要用在 roles 中)

元類(Metaclasses)


每個對象(包括任何基于類的對象)代理給它的元類的一個實例上伯病。你能通過 HOW 方法來獲取元類的任何對象, HOW 方法返回那個元類的實例造烁。 在 Perl 6 中, 一個"類"對象僅僅被認為是一個"空的"實例, 更合適的叫法是 "原型" 或 "泛型" 對象, 或僅僅叫 "類型對象"否过。 Perl 6 真的沒有任何名為 Class 的類。 各種各樣的類型是通過這些未定義的類型對象來命名的, 這被認為是和他們自己的實例化版本擁有相同的類型惭蟋。但是這樣的類型對象是惰性的, 并且不能管理類實例的狀態(tài)苗桂。

管理實例的實際對象是通過 HOW 語法所指向的元類對象。 所以當你說 "Dog"的時候, 你指的即是一個包又是一個類型對象, 后者指的是通過 HOW 來表示類的對象告组。 類型對象區(qū)別實例對象不是通過擁有不同的類型, 而是就誰被定義而言的煤伟。有些對象可能告訴你它們被定義了, 而其它對象可能告訴你它們沒有被定義。 那歸結于對象, 并取決于元對象如何選擇去分發(fā) .defined 方法木缝。

閉合類(Closed classes)


類默認是開放和非最終(non-final) 的, 但是它們能很容易地被整個程序閉合或定型, 而非被它們自己便锨。 然而使用動態(tài)加載或子程序的平臺可能不想批量閉合或定型類。(這特么都是什么?)

私有類


私有類能使用 my 來聲明; 在 Perl 6 中, 大部分隱私問題是使用詞法作用域(my)來處理的我碟。詞法默認很重要的事實也意味著類導入的任何名字默認也是私有的放案。

在 grammars 中, 不能使用 grammars 屬性, 所以你能從一個不相關的 grammar 中調用一個 grammar。這能通過在閉包中創(chuàng)建一個本地作用域的 grammars 來模仿那種行為矫俺。閉包捕獲的詞法變量就能用在像 grammars 屬性那樣的地方了吱殉。

類的成分


class聲明(特別地, role 合成)是嚴格的編譯時語句。特別地, 如果類聲明出現(xiàn)在嵌套作用域里面, 那么類聲明被約束為, 構成和任何可能的實現(xiàn)一樣厘托。所有的 roles 和 超類必須被限制為非重新裝訂的只讀值; 任何 traits 的參數(shù)會只在非拷貝上下文中被求值友雳。類聲明限定的名字是非重新裝訂的并且是只讀的, 所以它們能被用作超類。

匿名的類聲明


在匿名的類聲明中, 如果需要 :: 本身就代表了匿名類的名字:

class { ... }                    # ok
class is Mammal { ... }          # 錯誤
class :: is Mammal { ... }       # ok
class { also is Mammal; ... }    # also ok

方法


方法是類中使用 method 關鍵字聲明的子例程:

method doit ($a, $b, $c) { ... }
meyhod doit ($self: $a, $b, $c) { ... }
method doit (MyName $self: $a, $b, $c) { ... }
method doit (::?CLASS $self: $a, $b, $c) { ... }

調用者


調用者的聲明是可選的铅匹。你總是使用關鍵字 self來訪問當前調用者押赊。你不需要聲明調用者的類型, 因為調用者的詞法類是被任何事件知曉的, 因為方法必須聲明在調用者的類中, 盡管真實的(虛擬的)類型可能是詞法類型派生出來的類型。你可以聲明一個限制性更強的類類型, 但是那對于多態(tài)可能是壞事兒包斑。你可以顯式地使用詞法類型來type 調用者, 但是任何為此做的檢查會被優(yōu)化掉考杉,(當前的詞法導向的類總是可以命名為 ::?CLASS 即使在匿名類中或 roles 中)

S12-attributes/recursive.t lines 46–97

要標記一個顯式的調用者, 在它后面放上一個冒號就好了:

method doit ($x: $a, $b, $c) { ... }

如果你使用數(shù)組變量為 Array 類型聲明一個顯式的調用者, 你可以在列表上下文中直接使用它來生成它的元素

method push3 (@x: $a, $b, $c) { ... any(@x) ... }

注意 self項直接指向了方法所調用的對象上, 因此:

class A is Array {
    method m() { .say for self }
}
A.new(1, 2, 3).m; # 1\n2\n\3

會打印3行輸出。

私有方法


私有方法是使用 ! 聲明的:

[S12-methods/private.t lines 6–44]

method !think (Brain $self: $thought)

(這樣的方法對普通方法調用是完全不可見的, 實際上是使用不同的語法, 即使用 ! 代替 . 字符舰始。 看下面崇棠。)

方法作用域


不像大部分的其它聲明符, method聲明符不是默認為 our語義, 或者甚至 my 語義, 而是 has語義。所以, 不是安裝一個符號到詞法的或包的符號表中, 它們只是在當前類或 role 中通過調用它的元對象來安裝一個公共的或私有的方法丸卷。(同樣適用于 submethod 聲明符 — 查看下面的 "Submethod").

使用一個顯式的 has聲明符對聲明沒有影響枕稀。你可以在本地作用域中使用my或在當前包中使用 our來給方法安裝額外的別名。這些別名使用 &foo別名來命名, 并返回一個能叫做子例程的 Routine對象, 這時你必須提供期望的調用者作為第一個參數(shù)谜嫉。

方法調用


要使用普通的方法分發(fā)語義來調用普通的方法, 使用點語法記法或間接對象記法:

S12-methods/instance.t lines 13–243

$obj.doit(1,2,3)
doit $obj: 1, 2, 3

間接對象記法現(xiàn)在要求調用者后面要有一個冒號, 即使冒號后面沒有參數(shù):

S12-methods/indirect_notation.t lines 5–57

$handle.close;
close $handle:;

要拒絕方法調用并且只考慮 subs, 僅僅從調用行那兒省略冒號即可:

close($handle);
close $handle;

然而, 這兒內置IO類定義的方法 close ()是導出的, 它默認把 multi sub close (IO) 放在作用域中萎坷。因此, 如果 $handle對象是一個 IO 對象的話, 那么上面的兩個子例程調用仍舊被轉換成方法調用。

點調用記法可以省略調用者, 如果調用者是 $_:

.doit(1,2,3)

方法調用使用的是 C3 方法解析順序沐兰。

花哨的方法調用


注意對于私有方法沒有對應的記法哆档。

!doit(1,2,3)     # 錯, 會被解析為 not(doit(1,2,3))
self!doit(1,2,3) # ok

對于方法名有幾種間接的形式。你可以使用引起的字符串替換標識符, 它會被求值為引起, 引起的結果用作方法名住闯。

S12-methods/indirect_notation.t lines 58–76

$obj."$methodname"(1,2,3) # 使用 $methodname 的內容作為方法名
$obj.'$methodname'(1,2,3) # 沒有插值; 調用名字中帶有 $ 符號的方法

$obj!"$methodname"() # 間接調用私有方法名

在插值中, 雙引號形式不可以包含空白瓜浸。這在雙引號中以點結尾的字符串中達到用戶期望的那樣:

S02-literals/misc-interpolation.t lines 96–120

say "Foo = $foo.";

如果你真的想調用帶有空格的方法, 那你使用一個閉包插值來進行約束:

say "Foo = {$foo."a method"()}"; # OK
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末澳淑,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子插佛,更是在濱河造成了極大的恐慌杠巡,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件雇寇,死亡現(xiàn)場離奇詭異氢拥,居然都是意外死亡,警方通過查閱死者的電腦和手機锨侯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進店門嫩海,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人囚痴,你說我怎么就攤上這事出革。” “怎么了渡讼?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵骂束,是天一觀的道長。 經(jīng)常有香客問我成箫,道長展箱,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任蹬昌,我火速辦了婚禮混驰,結果婚禮上,老公的妹妹穿的比我還像新娘皂贩。我一直安慰自己栖榨,他們只是感情好,可當我...
    茶點故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布明刷。 她就那樣靜靜地躺著婴栽,像睡著了一般。 火紅的嫁衣襯著肌膚如雪辈末。 梳的紋絲不亂的頭發(fā)上愚争,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天,我揣著相機與錄音挤聘,去河邊找鬼轰枝。 笑死,一個胖子當著我的面吹牛组去,可吹牛的內容都是我干的鞍陨。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼从隆,長吁一口氣:“原來是場噩夢啊……” “哼诚撵!你這毒婦竟也來了缭裆?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤砾脑,失蹤者是張志新(化名)和其女友劉穎幼驶,沒想到半個月后艾杏,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體韧衣,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年购桑,在試婚紗的時候發(fā)現(xiàn)自己被綠了畅铭。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡勃蜘,死狀恐怖硕噩,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情缭贡,我是刑警寧澤炉擅,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站阳惹,受9級特大地震影響谍失,放射性物質發(fā)生泄漏。R本人自食惡果不足惜莹汤,卻給世界環(huán)境...
    茶點故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一快鱼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧纲岭,春花似錦抹竹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至喇闸,卻和暖如春兢孝,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背仅偎。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工跨蟹, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人橘沥。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓窗轩,卻偏偏與公主長得像,于是被迫代替她去往敵國和親座咆。 傳聞我的和親對象是個殘疾皇子痢艺,可洞房花燭夜當晚...
    茶點故事閱讀 43,446評論 2 348

推薦閱讀更多精彩內容

  • 1. Java基礎部分 基礎部分的順序:基本語法仓洼,類相關的語法,內部類的語法堤舒,繼承相關的語法色建,異常的語法,線程的語...
    子非魚_t_閱讀 31,597評論 18 399
  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理舌缤,服務發(fā)現(xiàn)箕戳,斷路器,智...
    卡卡羅2017閱讀 134,628評論 18 139
  • 從三月份找實習到現(xiàn)在国撵,面了一些公司陵吸,掛了不少,但最終還是拿到小米介牙、百度壮虫、阿里、京東环础、新浪囚似、CVTE、樂視家的研發(fā)崗...
    時芥藍閱讀 42,207評論 11 349
  • 允許的修飾符 有些修飾符能在所有允許的地方出現(xiàn), 但并非所有的都這樣. 通常, 影響 regex 編譯的修飾符(...
    焉知非魚閱讀 1,326評論 0 1
  • 說來也有趣搬素,大概五年前,那時候剛畢業(yè)不久魏保,可能是想錢想瘋了熬尺,也有個高大上點的理由:我想積累自己的未來,看了非常多理...
    阿拉希哥閱讀 1,064評論 1 48