前言
學(xué)習(xí)一門(mén)新的語(yǔ)言肯定是要從他的基本語(yǔ)法開(kāi)始,語(yǔ)法構(gòu)成了整個(gè)程序設(shè)計(jì)的基礎(chǔ),從語(yǔ)法中我們也可以看到這門(mén)語(yǔ)言的一些特性,但是話說(shuō)回來(lái),語(yǔ)法這東西,不同的語(yǔ)言大同小異,所以這也對(duì)語(yǔ)法的記憶造成了一定的難度,其實(shí)最好的方法應(yīng)該是旁邊有本書(shū),隨時(shí)可以拿過(guò)來(lái)查閱或者糾正。
Go 的初學(xué)者可能會(huì)有這樣的疑問(wèn):為什么 Go 的聲明語(yǔ)法與傳統(tǒng)的其他 C 家族編程語(yǔ)言不太一樣?在這篇文章中我們會(huì)比較這兩種不同的方式,并且也會(huì)解釋為什么。下面話不多說(shuō)了,來(lái)一起看看詳細(xì)的介紹吧。
C 變量
首先,讓我們說(shuō)說(shuō) C 中的語(yǔ)法。C 使用了一種不尋常的巧妙的方法來(lái)實(shí)現(xiàn)聲明語(yǔ)法。我們不是用什么特殊的語(yǔ)法來(lái)描述類(lèi)型,而是寫(xiě)一個(gè)表達(dá)式,這個(gè)表達(dá)式包含兩個(gè)部分:被聲明的變量和變量的類(lèi)型。
上面這行代碼聲明了一個(gè)類(lèi)型為 int 的變量 x。一般來(lái)說(shuō),為了弄清楚如何編寫(xiě)新變量的類(lèi)型,可以先寫(xiě)一個(gè)含基本類(lèi)型變量的表達(dá)式,然后將基本類(lèi)型放在左邊,將表達(dá)式放在右邊。
因此,下面的聲明:
描述的是 p 是一個(gè)指向 int 類(lèi)型的指針,因?yàn)?‘*p' 的類(lèi)型為 int。而 a 是一個(gè) int 類(lèi)型的數(shù)組,因?yàn)?‘a(chǎn)[3]' (這里請(qǐng)忽略下標(biāo)的值 3,它只是說(shuō)明數(shù)組的大小)的類(lèi)型是 int。
那函數(shù)呢?在最開(kāi)始的時(shí)候,C 的函數(shù)聲明是將 參數(shù)的類(lèi)型寫(xiě)在括號(hào)外面的,像這樣:
int main(argc, argv)
int argc;
char *argv[];
{ /* ... */ }
再一次,我們可以看到 main 是一個(gè)函數(shù),因?yàn)楸磉_(dá)式 main(argc, argv) 返回了一個(gè) int 類(lèi)型的值。現(xiàn)在大家比較習(xí)慣寫(xiě)成這樣:
int main(int argc, char *argv[]) { /* ... */ }
但是基本的結(jié)構(gòu)還是一樣的。
對(duì)于簡(jiǎn)單的類(lèi)型來(lái)說(shuō)這種巧妙的語(yǔ)法思想是能很好工作的,但是一旦類(lèi)型變得復(fù)雜就會(huì)令人感到困惑了。非常經(jīng)典的一個(gè)例子就是聲明一個(gè)函數(shù)指針。遵循著規(guī)則,你得到了下面的這種寫(xiě)法:
fp 是一個(gè)指向函數(shù)的指針,因?yàn)槿绻銓?xiě)一個(gè)表達(dá)式 (*fp)(a, b) 你會(huì)調(diào)用函數(shù)并得到一個(gè) int 類(lèi)型的值。那如果 fp 的其中一個(gè)入?yún)⑺旧硪彩且粋€(gè)函數(shù)呢?
int (*fp)(int (*ff)(int x, int y), int b)
這就變得開(kāi)始難以閱讀了。
當(dāng)然,我們可以在聲明一個(gè)函數(shù)的時(shí)候去掉參數(shù)名,那么 main 函數(shù)可以聲明成:
讓我們回想一下,argv 是這樣聲明的,
通過(guò)把變量名放在中間來(lái)聲明類(lèi)似 char *[] 這樣類(lèi)型的時(shí)候其實(shí)是令人困惑的。
然后我們?cè)賮?lái)看看如果我們將入?yún)⒆兞棵サ舻那闆r下 fp 函數(shù)的聲明是怎么樣的:
int (*fp)(int (*)(int, int), int)
無(wú)論將變量名放在內(nèi)部的哪里都不那么清晰明了。對(duì)于第一個(gè)入?yún)ⅲ?/p>
我想這不太容易能一眼看出是在聲明一個(gè)指向函數(shù)的指針。再進(jìn)一步,如果我們的返回值也是一個(gè)函數(shù)指針呢?
int (*(*fp)(int (*)(int, int), int))(int, int)
這根本就看不清聲明出來(lái)的 fp 到底是個(gè)啥玩意。。。
你自己也可以構(gòu)造出更多這類(lèi)詳細(xì)的例子,但是這些都說(shuō)明了 C 的聲明語(yǔ)法可能引入的一些困難。
不過(guò)還有一點(diǎn)需要提出。因?yàn)轭?lèi)型和聲明的語(yǔ)法是相同的,所以解析中間類(lèi)型的表達(dá)式是很困難的。這就是為什么 C 的類(lèi)型轉(zhuǎn)換總是用括號(hào)括起來(lái):
Go 語(yǔ)法
非 C 家族的編程語(yǔ)言通常使用不同的聲明類(lèi)型的語(yǔ)法:變量名通常放在前面,然后緊跟著一個(gè)冒號(hào)。因此我們上面的例子就變成了這樣:
x: int
p: pointer to int
a: array[3] of int
這些聲明是明確的,如果從左往右讀你會(huì)發(fā)現(xiàn)也是詳細(xì)的。Go 語(yǔ)言從中得到了啟發(fā),但為了簡(jiǎn)潔起見(jiàn),刪除了冒號(hào)和一些關(guān)鍵字:
這個(gè)例子中 [3]int 與如何在表達(dá)式中使用 a 這兩者似乎沒(méi)有直接的對(duì)應(yīng)。(后面一小節(jié)中我們會(huì)講到指針的。)你可以通過(guò)單獨(dú)的語(yǔ)法來(lái)獲得清晰的結(jié)果。
現(xiàn)在讓我們考慮下函數(shù)。讓我們把這個(gè)聲明寫(xiě)成 Go 的形式,盡管在 Go 中真正的 main 函數(shù)是沒(méi)有入?yún)⒌模?/p>
func main(argc int, argv []string) int
表面上這和 C 語(yǔ)言并沒(méi)什么不同,除了將字符數(shù)組改成了字符串形式。但是從左往右讀起來(lái)卻很順暢:
函數(shù) main 需要傳入一個(gè)整型和字符串切片并且返回一個(gè)整型。(譯者注:直到譯者看到這篇文章,譯者才發(fā)現(xiàn)原來(lái)這么寫(xiě)讀起來(lái)竟這么順暢。。。)
即便舍去變量名還是很明確——因?yàn)閷?duì)于類(lèi)型聲明上沒(méi)有位置的變化,所以也沒(méi)有什么困惑。
func main(int, []string) int
這種從左到右的風(fēng)格有一個(gè)優(yōu)點(diǎn):就算類(lèi)型變得越來(lái)越復(fù)雜,這種方式還是表現(xiàn)得很得當(dāng)。
舉個(gè)聲明函數(shù)變量的例子(類(lèi)似在 C 語(yǔ)言中的函數(shù)指針):
f func(func(int, int) int, int) int
或者如果 f 返回的也是一個(gè)函數(shù)(譯者注:邊寫(xiě)邊讀你會(huì)再次驚訝于這絲滑般的順暢感。。。):
f func(func(int, int) int, int) func(int, int) int
從左到右依然讀起來(lái)很順暢,并且當(dāng)變量名被聲明的時(shí)候也很明顯。
類(lèi)型和表達(dá)式的語(yǔ)法的不同點(diǎn)使得在 Go 中編寫(xiě)和調(diào)用閉包是那么的簡(jiǎn)單:
sum := func(a, b int) int { return a + b } (3, 4)
指針
指針這家伙總是表現(xiàn)得“與眾不同”一點(diǎn)。觀察下數(shù)組和切片,舉個(gè)例子,Go 的類(lèi)型語(yǔ)法將方括號(hào)放在類(lèi)型的左邊,但是賦值表達(dá)式語(yǔ)法卻是將其放在表達(dá)式的右邊:
為了讓大家有一種熟悉的感覺(jué),Go 的指針同樣延續(xù) C 語(yǔ)言中的 * 符號(hào),但是我們不能簡(jiǎn)單的將指針類(lèi)型也反轉(zhuǎn)一下。所以指針使用方式如下:
我們不能簡(jiǎn)單粗暴地改成這樣:
因?yàn)楹缶Y 會(huì)與乘法的 相混淆。那或許我們可以使用 ^,舉個(gè)例子:
但同樣的這個(gè)符號(hào)也已經(jīng)有其他含義了,類(lèi)型和表達(dá)式在前綴后綴的問(wèn)題上總是在許多方面使事情復(fù)雜化。舉個(gè)例子,
這是一種寫(xiě)法,但一旦以 * 打頭就必須用括號(hào)將其包住:
如果我們?cè)敢夥艞?* 作為指針語(yǔ)法,那么這些括號(hào)就不是必要的了。(譯者注:但還能有更好的指針語(yǔ)法嗎。。。)
所以 Go 的指針語(yǔ)法與熟悉的 C 語(yǔ)言是類(lèi)似的,但這個(gè)關(guān)聯(lián)也意味著我們不得不使用括號(hào)來(lái)消除語(yǔ)法中的類(lèi)型和表達(dá)式之間的差異。
總體而言,我們相信 Go 的類(lèi)型語(yǔ)法比 C 的要更容易理解,尤其是當(dāng)事情變得復(fù)雜的時(shí)候。
關(guān)于Go語(yǔ)言為何要采用這種倒序語(yǔ)法呢?
Go的設(shè)計(jì)者Rob Pike的一篇介紹Go聲明語(yǔ)法的文章給出了答案,其中談到了Go聲明語(yǔ)法的設(shè)計(jì)考量。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
您可能感興趣的文章:- Go語(yǔ)言中的Slice學(xué)習(xí)總結(jié)
- GO 語(yǔ)言學(xué)習(xí)指南
- Go語(yǔ)言學(xué)習(xí)筆記之反射用法詳解
- Go語(yǔ)言基礎(chǔ)學(xué)習(xí)教程
- Go語(yǔ)言函數(shù)學(xué)習(xí)教程
- golang新手不注意可能會(huì)出現(xiàn)的一些小問(wèn)題