Go 的類(lèi)型聲明的設(shè)計(jì)

Go 的類(lèi)型聲明的設(shè)計(jì)健民。

本篇文章為官方文檔 Go's Declaration Syntax 的翻譯抒巢。

引言

剛剛?cè)腴T(mén) Go 語(yǔ)言的菜鳥(niǎo)們常常會(huì)很疑惑,為什么類(lèi)型聲明的語(yǔ)法會(huì)與 C 語(yǔ)言家族建立的傳統(tǒng)不同秉犹。這篇文檔將會(huì)比較這兩種聲明的方式蛉谜,并解釋為什么 Go 語(yǔ)言的聲明語(yǔ)法要如此設(shè)計(jì)。

C 的語(yǔ)法

首先我們看看 C 的語(yǔ)法凤优。C 采用了一種不同尋常悦陋,但是很聰明的聲明語(yǔ)法。我們只需在帶有目標(biāo)變量名的表達(dá)式里指明該表達(dá)式本身的類(lèi)型即可筑辨,而不需要特定的聲明語(yǔ)法俺驶。因此

int x;

聲明了 x 變量,其類(lèi)型為 int :這個(gè)表達(dá)式 x 的類(lèi)型為 int 棍辕。一般情況下暮现,為了指明新變量的類(lèi)型,我們要寫(xiě)出一個(gè)含有我們要聲明的變量的表達(dá)式楚昭,并且這個(gè)表達(dá)式的值屬于某種基本類(lèi)型栖袋;我們把這個(gè)基本類(lèi)型寫(xiě)到表達(dá)式的左邊。

所以抚太,聲明

int *p;
int a[3];

指明了 p 是一個(gè)int類(lèi)型的指針塘幅,因?yàn)楸磉_(dá)式 *p的類(lèi)型為 int;而 a 是一個(gè) int 類(lèi)型的數(shù)組尿贫,因?yàn)?a[3]的類(lèi)型為 int(這里的索引值不用管电媳,它只是表明數(shù)組的長(zhǎng)度)。

那函數(shù)的類(lèi)型聲明呢庆亡?一開(kāi)始在 C 的函數(shù)聲明中匾乓,參數(shù)的類(lèi)型是寫(xiě)在括號(hào)外的,像下面這樣:

int main(argc, argv)
    int argc;
    char *argv[];
{ /* ... */ }

如前所述又谋,我們可以看到 main 之所以是函數(shù)拼缝,是因?yàn)楸磉_(dá)式 main(argc, argv) 返回 int娱局。在現(xiàn)代記法中我們會(huì)寫(xiě)作:

int main(int argc, char *argv[]) { /* ... */ }

因?yàn)榛镜慕Y(jié)構(gòu)是一樣的。

這種聰明的語(yǔ)法在簡(jiǎn)單類(lèi)型的聲明上表現(xiàn)不錯(cuò)咧七,但實(shí)際上很快就能讓人犯迷糊衰齐。著名的例子就是聲明函數(shù)指針。按照這套聲明規(guī)則猪叙,我們要寫(xiě)成:

int (*fp)(int a, int b);

這里 fp 之所以是一個(gè)函數(shù)指針是因?yàn)?(*fp)(a, b) 這個(gè)表達(dá)式將會(huì)調(diào)用一個(gè)函數(shù)娇斩,并返回 int 類(lèi)型的值。如果當(dāng) fp 的某個(gè)參數(shù)本身又是一個(gè)函數(shù)穴翩,情況會(huì)怎樣呢犬第?

int (*fp)(int (*ff)(int x, int y), int b)

這時(shí)候讀起來(lái)就點(diǎn)難了。

當(dāng)然芒帕,我們聲明函數(shù)時(shí)是可以忽略參數(shù)名的歉嗓,因此 main 函數(shù)可以聲明為:

int main(int, char *[])

回想一下,之前 argv 是這樣聲明的:

char *argv[]

所以你其實(shí)是從聲明的中間去掉變量名背蟆,從而構(gòu)造出其變量類(lèi)型鉴分。這樣看起來(lái)非常不直觀(guān),你聲明某個(gè) char *[] 類(lèi)型的變量的時(shí)候带膀,竟然要把變量名放在了變量類(lèi)型的中間志珍。

如果我們忽略掉 fp 所有的參數(shù)名會(huì)怎樣呢:

int (*fp)(int (*)(int, int), int)

你不僅不能直觀(guān)地知道參數(shù)名原本應(yīng)該放在哪里:

int (*)(int, int)

而且它不能很清楚地表達(dá)出,這是一個(gè)函數(shù)指針聲明垛叨。我們接著看看伦糯,如果返回值也是個(gè)函數(shù)指針會(huì)怎么樣?

int (*(*fp)(int (*)(int, int), int))(int, int)

這已經(jīng)很難看出是關(guān)于 fp 的聲明了嗽元。

你自己還可以構(gòu)建出比這更復(fù)雜的例子敛纲,但上面的例子已經(jīng)足以解釋 C 的聲明語(yǔ)法引入的復(fù)雜性了。

還有一點(diǎn)需要指出剂癌,由于類(lèi)型語(yǔ)法和聲明語(yǔ)法是一樣的淤翔,要解析中間帶有類(lèi)型的表達(dá)式會(huì)有些難度。這也就是為什么佩谷,例如 C 在做類(lèi)型轉(zhuǎn)換的時(shí)候總是要把類(lèi)型用括號(hào)括起來(lái)旁壮,像這樣

(int)M_PI

Go 的語(yǔ)法

非 C 家族的語(yǔ)言通常在聲明時(shí)使用一種不同的類(lèi)型語(yǔ)法。雖然它們都有一個(gè)分割的符號(hào)谐檀,但通常還是變量名先出現(xiàn)抡谐,然后常常跟著一個(gè)冒號(hào)。按照這樣來(lái)寫(xiě)稚补,我們上面的所舉的例子就會(huì)變成下面這樣(一種虛構(gòu)的童叠,用于說(shuō)明的語(yǔ)言):

x: int
p: pointer to int
a: array[3] of int

這樣的聲明即便有些冗長(zhǎng)框喳,當(dāng)至少是明確的 —— 你只需從左向右讀就行课幕。Go 語(yǔ)言所采用的方案就是以此為基礎(chǔ)的厦坛,但為了追求簡(jiǎn)潔,Go 語(yǔ)言丟掉了冒號(hào)并去掉了部分關(guān)鍵詞:

x int
p *int
a [3]int

[3]int 和表達(dá)式中 a 的用法沒(méi)有直接的對(duì)應(yīng)關(guān)系(我們?cè)谙乱还?jié)會(huì)回過(guò)頭來(lái)探討指針的問(wèn)題)乍惊。你付出了的語(yǔ)法不統(tǒng)一的代價(jià)杜秸,但獲得更明確的語(yǔ)法。

下面我們來(lái)考慮函數(shù)的問(wèn)題润绎。雖然在 Go 語(yǔ)言里撬碟,main 函數(shù)實(shí)際上沒(méi)有參數(shù),但是我們直接改編一下之前的 main 函數(shù)的聲明:

func main(argc int, argv []string) int

除了 char 類(lèi)型的數(shù)組變成了 string 外莉撇,粗略看來(lái)和 C 沒(méi)什么不同呢蛤,不過(guò)自左向右讀起來(lái)非常順暢:

  • main 函數(shù)接受一個(gè) int 變量和 string 類(lèi)型的 slice 變量,并返回一個(gè)int 棍郎。
  • 如果此時(shí)把參數(shù)名去掉其障,它還是很明確 —— 因?yàn)閰?shù)名總在類(lèi)型的前面,所以不會(huì)引起混淆涂佃。
func main(int, *[]byte) int1

這種自左向右的聲明的一個(gè)好處在于励翼,當(dāng)類(lèi)型變得更復(fù)雜時(shí),它仍然表示得很明確辜荠。下面是一個(gè)函數(shù)變量的聲明(相當(dāng)于 C 里的函數(shù)指針):

f func(func(int,int) int, int) int

或者當(dāng)它返回一個(gè)函數(shù)時(shí):

f func(func(int,int) int, int) func(int, int) int

上面的聲明讀起來(lái)還是很明確汽抚,自左向右,當(dāng)前聲明的是哪一個(gè)變量名 —— 因?yàn)樽兞棵肋h(yuǎn)在首位伯病。

類(lèi)型語(yǔ)法和表達(dá)式語(yǔ)法帶來(lái)的差別使得在 Go 語(yǔ)言里調(diào)用閉包也變得更簡(jiǎn)單:

sum := func(a, b int) int { return a+b } (3, 4)

指針

指針有些例外造烁。注意在數(shù)組 (array)和切片 (slice) 中,Go 的類(lèi)型語(yǔ)法把方括號(hào)放在了類(lèi)型的左邊狱从,但是在表達(dá)式語(yǔ)法中卻又把方括號(hào)放到了右邊:

var a []int
x = a[1]

類(lèi)似的膨蛮,Go 的指針沿用了 C 的 * 記法,但是指針類(lèi)型的寫(xiě)法就不是像上面一樣反過(guò)來(lái)季研。指針要寫(xiě)成這樣:

var p *int
x = *p

而不能寫(xiě)成下面這樣:

var p *int
x = p*

因?yàn)楹缶Y的 * 可能會(huì)和乘法運(yùn)算混淆敞葛,也許我們可以改用 Pascal 的 ^ 標(biāo)記,像這樣

var p ^int
x = p^

我們也許還真的應(yīng)該把 * 像上面這樣改成 ^ (然后用另一個(gè)運(yùn)算符代表 xor)与涡,因?yàn)樵陬?lèi)型和表達(dá)式中的 * 前綴確實(shí) 許多事都搞得有點(diǎn)復(fù)雜惹谐。例如,雖然我們可以像下面這樣寫(xiě)

[]int("hi")

但在轉(zhuǎn)換時(shí)驼卖,如果類(lèi)型是以 * 開(kāi)頭的氨肌,就得加上括號(hào):

(*int)(nil)

如果有一天我們?cè)敢夥艞売?*作為指針語(yǔ)法的話(huà),那么上面的括號(hào)就可以省略了酌畜。

因此 Go 的指針語(yǔ)法和 C 是相似的怎囚,但這種相似也意味著我們無(wú)法徹底避免在文法中使用括號(hào)來(lái)避免類(lèi)型和表達(dá)式的歧義。

綜上所述,我們相信 Go 的類(lèi)型語(yǔ)法要比 C 的容易懂恳守。特別是當(dāng)類(lèi)型比較復(fù)雜時(shí)考婴。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市催烘,隨后出現(xiàn)的幾起案子沥阱,更是在濱河造成了極大的恐慌,老刑警劉巖伊群,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件考杉,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡舰始,警方通過(guò)查閱死者的電腦和手機(jī)崇棠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)丸卷,“玉大人易茬,你說(shuō)我怎么就攤上這事〖袄希” “怎么了抽莱?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)骄恶。 經(jīng)常有香客問(wèn)我食铐,道長(zhǎng),這世上最難降的妖魔是什么僧鲁? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任虐呻,我火速辦了婚禮,結(jié)果婚禮上寞秃,老公的妹妹穿的比我還像新娘斟叼。我一直安慰自己,他們只是感情好春寿,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布朗涩。 她就那樣靜靜地躺著,像睡著了一般绑改。 火紅的嫁衣襯著肌膚如雪谢床。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,185評(píng)論 1 284
  • 那天厘线,我揣著相機(jī)與錄音识腿,去河邊找鬼。 笑死造壮,一個(gè)胖子當(dāng)著我的面吹牛渡讼,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼成箫,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼栖雾!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起伟众,我...
    開(kāi)封第一講書(shū)人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎召廷,沒(méi)想到半個(gè)月后凳厢,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了果覆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片慢叨。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖啰扛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤本冲,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站劫扒,受9級(jí)特大地震影響檬洞,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜沟饥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一添怔、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧贤旷,春花似錦广料、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至盅藻,卻和暖如春糜颠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背萧求。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工其兴, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人夸政。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓元旬,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子匀归,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容