python和go語(yǔ)言有區(qū)別:1、Python語(yǔ)法使用縮進(jìn)來(lái)指示代碼塊;Go語(yǔ)法基于打開和關(guān)閉括號(hào);2、Python是基于面向?qū)ο缶幊痰亩喾妒秸Z(yǔ)言;Go是基于并發(fā)編程范式的過(guò)程編程語(yǔ)言。3、Python是動(dòng)態(tài)類型語(yǔ)言,Go是靜態(tài)類型語(yǔ)言。
目前創(chuàng)新互聯(lián)已為上1000家的企業(yè)提供了網(wǎng)站建設(shè)、域名、網(wǎng)頁(yè)空間、成都網(wǎng)站托管、企業(yè)網(wǎng)站設(shè)計(jì)、惠州網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長(zhǎng),共同發(fā)展。
Go語(yǔ)言(又稱 Golang)是 Google 的 Robert Griesemer,Rob Pike 及 Ken Thompson 開發(fā)的一種靜態(tài)強(qiáng)類型、編譯型語(yǔ)言。Go 語(yǔ)言語(yǔ)法與 C 相近,但功能上有:內(nèi)存安全,GC(垃圾回收),結(jié)構(gòu)形態(tài)以及 CSP-style 并發(fā)計(jì)算。
python是一種廣泛使用的具有動(dòng)態(tài)語(yǔ)義的解釋型,面向?qū)ο蟮母呒?jí)編程語(yǔ)言。
Python是一種面向?qū)ο蟮母呒?jí)編程語(yǔ)言,具有集成的動(dòng)態(tài)語(yǔ)義,主要用于Web和應(yīng)用程序開發(fā)。它在快速應(yīng)用程序開發(fā)領(lǐng)域極具吸引力,因?yàn)樗峁﹦?dòng)態(tài)類型和動(dòng)態(tài)綁定選項(xiàng)。
Python是一種解釋型語(yǔ)言,這意味著用Python編寫的程序不需要事先編譯就可以運(yùn)行,從而可以輕松地測(cè)試小段代碼并使用Python編寫的代碼更容易在平臺(tái)之間移動(dòng)。
python和go語(yǔ)言的區(qū)別:
1、語(yǔ)法
Python的語(yǔ)法使用縮進(jìn)來(lái)指示代碼塊。Go的語(yǔ)法基于打開和關(guān)閉括號(hào)。
2、范例
Python是一種基于面向?qū)ο缶幊痰亩喾妒剑钍胶秃瘮?shù)式編程語(yǔ)言。它堅(jiān)持這樣一種觀點(diǎn),即如果一種語(yǔ)言在某些情境中表現(xiàn)出某種特定的方式,理想情況下它應(yīng)該在所有情境中都有相似的作用。但是,它又不是純粹的OOP語(yǔ)言,它不支持強(qiáng)封裝,這是OOP的主要原則之一。
Go是一種基于并發(fā)編程范式的過(guò)程編程語(yǔ)言,它與C具有表面相似性。實(shí)際上,Go更像是C的更新版本。
3、并發(fā)
Python沒有提供內(nèi)置的并發(fā)機(jī)制,而Go有內(nèi)置的并發(fā)機(jī)制。
4、類型化
Python是動(dòng)態(tài)類型語(yǔ)言,而Go是一種靜態(tài)類型語(yǔ)言,它實(shí)際上有助于在編譯時(shí)捕獲錯(cuò)誤,這可以進(jìn)一步減少生產(chǎn)后期的嚴(yán)重錯(cuò)誤。
5、安全性
Python是一種強(qiáng)類型語(yǔ)言,它是經(jīng)過(guò)編譯的,因此增加了一層安全性。Go具有分配給每個(gè)變量的類型,因此,它提供了安全性。但是,如果發(fā)生任何錯(cuò)誤,用戶需要自己運(yùn)行整個(gè)代碼。
6、管理內(nèi)存
Go允許程序員在很大程度上管理內(nèi)存。而,Python中的內(nèi)存管理完全自動(dòng)化并由Python VM管理;它不允許程序員對(duì)內(nèi)存管理負(fù)責(zé)。
7、庫(kù)
與Go相比,Python提供的庫(kù)數(shù)量要大得多。然而,Go仍然是新的,并且還沒有取得很大進(jìn)展。
8、速度:
Go的速度遠(yuǎn)遠(yuǎn)超過(guò)Python。
Python與Golang對(duì)比:
1、特點(diǎn):
Golang
①靜態(tài)強(qiáng)類型、編譯型、并發(fā)型
靜態(tài)類型語(yǔ)言,但是有動(dòng)態(tài)語(yǔ)言的感覺。(靜態(tài)類型的語(yǔ)言就是可以在編譯的時(shí)候檢查出來(lái)隱藏的大多數(shù)問(wèn)題,動(dòng)態(tài)語(yǔ)言的感覺就是有很多的包可以使用,寫起來(lái)的效率很高)
可直接編譯成機(jī)器碼,不依賴其他庫(kù),glibc的版本有一定要求,部署就是扔一個(gè)文件上去就完成了。
語(yǔ)言層面支持并發(fā),這個(gè)就是Go最大的特色,天生的支持并發(fā)。Go就是基因里面支持的并發(fā),可以充分地利用多核,很容易地使用并發(fā)。
②垃圾回收機(jī)制
內(nèi)置runtime,支持垃圾回收,這屬于動(dòng)態(tài)語(yǔ)言的特性之一吧,雖然目前來(lái)說(shuō)GC(內(nèi)存垃圾回收機(jī)制)不算完美,但是足以應(yīng)付我們所能遇到的大多數(shù)情況,特別是Go1.1之后的GC。
③支持面向?qū)ο缶幊?/p>
有接口類型和實(shí)現(xiàn)類型的概念,但是用嵌入替代了繼承。
④豐富的標(biāo)準(zhǔn)庫(kù)
Go目前已經(jīng)內(nèi)置了大量的庫(kù),特別是網(wǎng)絡(luò)庫(kù)非常強(qiáng)大。
⑤內(nèi)嵌C支持
Go里面也可以直接包含C代碼,利用現(xiàn)有的豐富的C庫(kù)
Python
①解釋型語(yǔ)言
程序不需要在運(yùn)行前編譯,在運(yùn)行程序的時(shí)候才翻譯,專門的解釋器負(fù)責(zé)在每個(gè)語(yǔ)句執(zhí)行的時(shí)候解釋程序代碼。這樣解釋型語(yǔ)言每執(zhí)行一次就要翻譯一次,效率比較低。
②動(dòng)態(tài)數(shù)據(jù)類型
支持重載運(yùn)算符,也支持泛型設(shè)計(jì)。(運(yùn)算符重載,就是對(duì)已有的運(yùn)算符重新進(jìn)行定義,賦予其另一種功能,以適應(yīng)不同的數(shù)據(jù)類型。泛型設(shè)計(jì)就是定義的時(shí)候不需要指定類型,在客戶端使用的時(shí)候再去指定類型)
③完全面向?qū)ο蟮恼Z(yǔ)言
函數(shù),模塊,數(shù)字,字符串都是對(duì)象,在Python中,一切接對(duì)象
完全支持繼承,重載,多重繼承
④擁有強(qiáng)大的標(biāo)準(zhǔn)庫(kù)
Python語(yǔ)言的核心只包含數(shù)字,字符串,列表,元祖,字典,集合,文件等常見類型和函數(shù),而由Python標(biāo)準(zhǔn)庫(kù)提供了系統(tǒng)管理,網(wǎng)絡(luò)通信,文本處理,數(shù)據(jù)庫(kù)接口,圖形系統(tǒng),XML處理等額外的功能。
⑤社區(qū)提供了大量第三方庫(kù)
Python 社區(qū)提供了大量的第三方模塊,使用方式與標(biāo)準(zhǔn)庫(kù)類似。它們的功能覆蓋 科學(xué)計(jì)算、人工智能、機(jī)器學(xué)習(xí)、Web 開發(fā)、數(shù)據(jù)庫(kù)接口、圖形系統(tǒng) 多個(gè)領(lǐng)域。
2、應(yīng)用
Python
①網(wǎng)絡(luò)編程
web應(yīng)用,網(wǎng)絡(luò)爬蟲
②數(shù)據(jù)分析和機(jī)器學(xué)習(xí)
③自動(dòng)化測(cè)試
④自動(dòng)化運(yùn)維
Golang
①服務(wù)器編程
處理日志、數(shù)據(jù)打包、虛擬機(jī)處理、文件系統(tǒng)等。
②分布式系統(tǒng),數(shù)據(jù)庫(kù)代理器等
③網(wǎng)絡(luò)編程
這一塊目前應(yīng)用最廣,包括Web應(yīng)用、API應(yīng)用、下載應(yīng)用。
④內(nèi)存數(shù)據(jù)庫(kù)
如google開發(fā)的groupcache,couchbase的部分組件。
⑥云平臺(tái)
Go語(yǔ)言和Python學(xué)哪個(gè)好?
Python 可以很好地集成到企業(yè)級(jí)應(yīng)用中,可用于機(jī)器語(yǔ)言和 AI 應(yīng)用。Go 語(yǔ)言的特點(diǎn)表明它具備輕量級(jí)線程實(shí)現(xiàn)(Goroutine)、智能標(biāo)準(zhǔn)庫(kù)、強(qiáng)大的內(nèi)置安全性,且可使用最簡(jiǎn)語(yǔ)法進(jìn)行編程。Go 在大部分案例中領(lǐng)先,被認(rèn)為是 Python 的有效替代方案。開發(fā)者在選擇編程語(yǔ)言時(shí),應(yīng)考慮開發(fā)項(xiàng)目的性質(zhì)和規(guī)模,以及所需的技能組合。
放下個(gè)人偏見和喜好,從優(yōu)點(diǎn)和功能的角度來(lái)評(píng)價(jià)兩種語(yǔ)言。不管選擇了哪種語(yǔ)言,Go 和 Python 都在持續(xù)演進(jìn)。盡管在大多數(shù)情況下 Golang 可能是更好的選擇,但Python語(yǔ)言也是不斷更新迭代的。以上就是本次分享的全部?jī)?nèi)容,如果你也想學(xué)習(xí)一門編程語(yǔ)言,可以考慮下 六星教育 ,這里的課程體系,師資團(tuán)隊(duì)以及售后服務(wù),一定不會(huì)讓你失望!
隨著 PHP 有著越來(lái)越深入的了解,以及遇到越來(lái)越多的不同業(yè)務(wù)時(shí),使用 PHP 總會(huì)讓我有一種莫名的無(wú)力感。當(dāng)然,并不是我一個(gè)人在使用 PHP 的時(shí)候遇到了問(wèn)題。事實(shí)上,每個(gè)略微有一些經(jīng)驗(yàn),接觸過(guò)一些需求的人都會(huì)有同樣的困惑。各種配合 LAMP(或者LNMP?)架構(gòu)的后端技術(shù)也因此被發(fā)明或被發(fā)現(xiàn),進(jìn)而整合到 PHP 的開發(fā)的技術(shù)體系中。從簡(jiǎn)單的 Memcached作為數(shù)據(jù)中轉(zhuǎn),cron 后端定時(shí)處理;到 Gearman、RabbitMQ 這些隊(duì)列神器;最近 Laruence 甚至封裝了利用 libcurl 的異步特性實(shí)現(xiàn)并發(fā) RPC 調(diào)用的 yar 擴(kuò)展。幾乎整個(gè)社區(qū)都在尋找 PHP 的摩西之路。好吧,說(shuō)了一大堆,回歸主題。之前我寫了一篇英文練筆《Why you PHP guys should learn Golang》,獲得不少國(guó)際友人的關(guān)注。排除拼寫和語(yǔ)法被他們?cè)嵅⊥猓饕怯性S多朋友覺得我沒把事情說(shuō)清楚。所以這里我用母語(yǔ)重新聊聊這個(gè)事情,只是這些國(guó)際友人什么時(shí)候能學(xué)會(huì)閱讀中文呢?;)Go 或者 Golang,是由 Google 支持的快速、一致、穩(wěn)定的,有活躍的社區(qū)支持的開源編程語(yǔ)言。越來(lái)越多的應(yīng)用選擇使用 Golang 進(jìn)行構(gòu)建。雖然 Rob Pike 說(shuō)“… 我們希望 C++ 程序員來(lái)了解 Go 并作為一個(gè)可選的語(yǔ)言 …”,不過(guò)我真得認(rèn)為:PHPer 應(yīng)當(dāng)學(xué)習(xí) Golang! 接下來(lái)我們就來(lái)談?wù)勗?。容易學(xué)習(xí)PHP 相當(dāng)容易學(xué)習(xí)。Golang 也是!在這點(diǎn)上,一群大老外對(duì)我的觀點(diǎn)進(jìn)行了猛烈的抨擊。他們認(rèn)為我羞辱了 PHPer,說(shuō)得好像只有簡(jiǎn)單的東西 PHPer 才能學(xué)會(huì)一樣。但是,這難道不是事實(shí)嗎?或者換個(gè)說(shuō)法:像我一樣的喜歡 PHP 的人,或多或少都會(huì)更喜歡簡(jiǎn)單的東西。PHP 的語(yǔ)法接近 C 族編程語(yǔ)言(C/C++/Java等等)。如果有這些語(yǔ)言的經(jīng)驗(yàn),在第一次遇到 PHP 的時(shí)候立刻就能開始上手編寫代碼。在我看來(lái),編寫 PHP 代碼或許更加考驗(yàn)程序員的記憶力,而不是智力(當(dāng)你面對(duì)各種不同風(fēng)格的函數(shù)定義、各種擴(kuò)展的特殊約定時(shí),你一定會(huì)相當(dāng)認(rèn)同我的觀點(diǎn))。Golang 同樣是一個(gè) C 族編程語(yǔ)言。呃,或者有一些不同吧。例如關(guān)鍵字 “for”,功能上和 PHP 的接近,但是沒有括號(hào)。條件語(yǔ)句 “if” 同樣無(wú)需括號(hào)??梢蚤喿x Effective Go 了解更多內(nèi)容。Golang 只有 3025 個(gè)關(guān)鍵字和 47 個(gè)操作符號(hào)、分隔符號(hào)或其他特殊標(biāo)記。記住這些標(biāo)記確實(shí)不需要什么特別的努力。精巧的類型系統(tǒng)相當(dāng)容易使用。實(shí)用的,具有方法的結(jié)構(gòu)體類型代替了笨重的對(duì)象系統(tǒng)。接口的設(shè)計(jì)是 Golang 中我最喜歡的部分。當(dāng)完成了《Go 指南》的學(xué)習(xí)之后,利用 PHP 積累的經(jīng)驗(yàn),立刻就可以開始使用 Golang 處理一些簡(jiǎn)單的任務(wù)。容易使用PHP 腳本是由 SAPI 組件進(jìn)行解析執(zhí)行的,如 Web 服務(wù)器模塊、PHP-FPM 或者 CLI。部署 PHP 所需要的全部東西就是一個(gè) SAPI 環(huán)境。配置這個(gè)環(huán)境對(duì)于新手來(lái)說(shuō)可能是學(xué)習(xí) PHP 過(guò)程中最為困難的部分。所有的 Golang 代碼會(huì)編譯和鏈接為本地碼。所以除了編譯環(huán)境,執(zhí)行時(shí)無(wú)需再為其進(jìn)行任何特別的部署。對(duì)比 PHP 環(huán)境的配置,這要簡(jiǎn)單很多。你真得認(rèn)為配置 PHP 環(huán)境很復(fù)雜嗎?我不覺得,真的!而配置 Golang 編譯環(huán)境比那還要簡(jiǎn)單點(diǎn)。我確信已經(jīng)有大量的 Golang 相關(guān)的書籍、文章介紹過(guò)如何進(jìn)行編譯環(huán)境的配置了。為了更加清晰,我這里梳理一下思路。
有三個(gè)步驟需要處理:下載Golang 的源代碼;根據(jù)《[翻譯]Go 環(huán)境設(shè)置》的提示設(shè)置環(huán)境變量;運(yùn)行源代碼 src 目錄中的 all.bash?;蛘咭徊降轿唬菏褂枚M(jìn)制包進(jìn)行安裝。然后就會(huì)得到一個(gè)叫做“go”的工具集合。使用“go”工具和使用 PHP 的 CLI 工具一樣簡(jiǎn)單。《[翻譯]go 工具》對(duì)此進(jìn)行了詳細(xì)的解釋。PHP 的迷思如果一個(gè)編程語(yǔ)言容易學(xué)習(xí)和使用,我們是不是就應(yīng)當(dāng)學(xué)習(xí)它呢?有許多容易學(xué)習(xí)和使用的編程語(yǔ)言。難道要把它們都學(xué)一遍?答案是顯然的:NO!但是 呢?只是因?yàn)樗芸?!是的,我在開玩笑,但是這是真的。無(wú)論如何先從 PHP 自身談起吧。PHP “原本是為了開發(fā)動(dòng)態(tài)的 Web 頁(yè)面而設(shè)計(jì)的服務(wù)器端通用語(yǔ)言(Wikipedia)”。PHP 一個(gè)重要的特性就是可以嵌入到 HMTL 中。代碼編寫在“?php … ?”標(biāo)簽內(nèi);HTML 寫在標(biāo)簽外。它有一個(gè)強(qiáng)大的擴(kuò)展系統(tǒng)。擴(kuò)展使用 C 調(diào)用 Zend API 編寫。數(shù)據(jù)的處理實(shí)際上要利用這些擴(kuò)展完成。在我看來(lái),PHP 是世界上最好的模板語(yǔ)言。但是當(dāng)積累了一些 PHP 的經(jīng)驗(yàn),并且開始面對(duì)一些更加復(fù)雜的 Web 應(yīng)用時(shí),你一定會(huì)對(duì) PHP 產(chǎn)生一種無(wú)力的感覺。它沒有內(nèi)建的并行機(jī)制,沒有線程、進(jìn)程(你真得認(rèn)為那個(gè)簡(jiǎn)陋的進(jìn)程控制可以不加改造的用在高并發(fā)的生產(chǎn)環(huán)境?),或者其他某“程”。一個(gè)慢數(shù)據(jù)源可以阻塞整個(gè)頁(yè)面的處理。消息隊(duì)列、緩存、代理……系統(tǒng)開始不僅僅是 PHP 這么單純,還包括了許多服務(wù)和系統(tǒng)組件。這時(shí),PHP 只處理很少的業(yè)務(wù)邏輯,成為真正的模板語(yǔ)言了。PHPer 們總是在尋找解決這一問(wèn)題的辦法,如“PHP multithread”或者PHP RPC 并發(fā)框架。我很難說(shuō)哪種會(huì)更好一些。不過(guò)我肯定你會(huì)需要選擇一些編程語(yǔ)言用于后端工作的開發(fā)。就我自己的經(jīng)驗(yàn),我嘗試過(guò) C(一直在和 malloc/free 進(jìn)行搏斗)/Java(陷入到了 jar 地獄中)/Python(從來(lái)沒能做到 Pythonic 不說(shuō),還總是在錯(cuò)誤的類型中打轉(zhuǎn))……如果想要獲得性能,就得同內(nèi)存管理進(jìn)行搏斗;如果用 GC,就得部署和調(diào)優(yōu) VM;當(dāng)獲得便利性的時(shí)候,同時(shí)也是走在刀尖上,一個(gè)小錯(cuò)誤就引起巨大的災(zāi)難……每個(gè)都有優(yōu)勢(shì),同樣每個(gè)都有問(wèn)題。好吧!現(xiàn)在回到 Golang!Golang 有 GC,無(wú)需關(guān)心內(nèi)存管理(或者可以用較少的精力去關(guān)注它)。代碼被編譯為本地碼,因此“cp”和“mv”就是部署 Golang 編寫的應(yīng)用所需要的全部工具。噢,我剛才已經(jīng)說(shuō)過(guò)了,Golang 是一個(gè)具有靜態(tài)類型系統(tǒng)的編譯語(yǔ)言。所以你沒有機(jī)會(huì)弄亂變量的類型。當(dāng)然,PHPer 應(yīng)該學(xué)習(xí) Golang 的一個(gè)重要原因是“轉(zhuǎn)到Go 是因?yàn)樗麄儾⑽捶艞壧嗟谋磉_(dá)能力,但是獲得了性能,并且與并發(fā)共舞(Rob Pike)”?!禬hy Not Go?(英文)》對(duì)此進(jìn)行了深入的分析。我可以分享一些我的經(jīng)驗(yàn):有一個(gè) Gearman 的worker 用于處理后端數(shù)據(jù)。PHP 通過(guò)其 API 連接到 Gearman 的 Job Server 向 worker 發(fā)起請(qǐng)求。最初 worker 是使用 python 編寫的(還有更加原始的版本,PHP 的,但是你能想像它工作起來(lái)……唉,不說(shuō)了……)。這個(gè)版本有許多的問(wèn)題(是我們自己的問(wèn)題,不關(guān) Python 的事),但是至少它能工作。后來(lái)用 Golang 重寫了這個(gè) worker。為此我開發(fā)了 Golang 的 Gearman API,并使用 Zend API 編寫了一個(gè)在 Golang 中執(zhí)行 PHP 腳本的包。然后將它們放在一起:一個(gè)可以執(zhí)行 PHP 的 Gearman worker。它已經(jīng)工作了一段時(shí)間了,看起來(lái)還不錯(cuò)!哦,受到 Yar 的啟發(fā),這里還有一個(gè) Golang 編寫的 RPC 合并器,用來(lái)合并 PHP 腳本中的 RPC 調(diào)用?,F(xiàn)在還是個(gè)玩具,不過(guò)或許日后能用得著。這其實(shí)是將 Golang 的 channel 當(dāng)作消息隊(duì)列來(lái)用。我在《Golang:有趣的 channel 應(yīng)用》中對(duì)此有一些說(shuō)明。世界真美好啊。謝謝 Golang!無(wú)論如何,大多數(shù) PHPer 在進(jìn)行后端開發(fā)的時(shí)候都會(huì)需要學(xué)習(xí)一些其他語(yǔ)言。如果你正在尋找,或者已經(jīng)嘗試了一些其他語(yǔ)言。為什么不來(lái)試試 Golang?它真得可以讓你的生活更加輕松和快樂。讓你可以有更多的時(shí)間陪伴你的家人和朋友,吃你愛吃的東西,去你想去的地方。貌似我還是沒說(shuō)清楚啊?好吧,沒關(guān)系,在下個(gè)月的中國(guó)軟件開發(fā)者大會(huì)上再跟大家就這個(gè)話題做一個(gè)探討吧。
“我們走吧”“讓我們走”“讓我們一起走”在句子理解意思上都沒有多大分別,都可以作為“Let's go.”的正確翻譯。
翻譯講究的是正確傳達(dá)原句的意思,增減一兩個(gè)詞語(yǔ)并不會(huì)造成對(duì)原句的錯(cuò)誤理解,因此有時(shí)候?yàn)榱司湟獾耐?,為了使翻譯出來(lái)的句子更符合我們?nèi)粘5恼f(shuō)話習(xí)慣,這樣靈活的變動(dòng)是可以鼓勵(lì)的。
其中,在甲語(yǔ)和乙語(yǔ)中,“翻”是指的這兩種語(yǔ)言的轉(zhuǎn)換,即先把一句甲語(yǔ)轉(zhuǎn)換為一句乙語(yǔ),然后再把一句乙語(yǔ)轉(zhuǎn)換為甲語(yǔ);“譯”是指這兩種語(yǔ)言轉(zhuǎn)換的過(guò)程,把甲語(yǔ)轉(zhuǎn)換成乙語(yǔ),在譯成當(dāng)?shù)卣Z(yǔ)言的文字中,進(jìn)而明白乙語(yǔ)的含義。
拓展資料:
翻譯是在準(zhǔn)確、通順的基礎(chǔ)上,把一種語(yǔ)言信息轉(zhuǎn)變成另一種語(yǔ)言信息的行為。翻譯是將一種相對(duì)陌生的表達(dá)方式,轉(zhuǎn)換成相對(duì)熟悉的表達(dá)方式的過(guò)程。其內(nèi)容有語(yǔ)言、文字、圖形、符號(hào)和視頻翻譯。
參考資料:
百度百科_翻譯
go14是去14意思。go14翻譯為去14,該數(shù)組可以由零個(gè)或多個(gè)元素組成,數(shù)組的長(zhǎng)度是固定的,在Go語(yǔ)言中很少直接使用數(shù)組。
Go 由于不支持泛型而臭名昭著,但最近,泛型已接近成為現(xiàn)實(shí)。Go 團(tuán)隊(duì)實(shí)施了一個(gè)看起來(lái)比較穩(wěn)定的設(shè)計(jì)草案,并且正以源到源翻譯器原型的形式獲得關(guān)注。本文講述的是泛型的最新設(shè)計(jì),以及如何自己嘗試泛型。
例子
FIFO Stack
假設(shè)你要?jiǎng)?chuàng)建一個(gè)先進(jìn)先出堆棧。沒有泛型,你可能會(huì)這樣實(shí)現(xiàn):
type?Stack?[]interface{}func?(s?Stack)?Peek()?interface{}?{
return?s[len(s)-1]
}
func?(s?*Stack)?Pop()?{
*s?=?(*s)[:
len(*s)-1]
}
func?(s?*Stack)?Push(value?interface{})?{
*s?=?
append(*s,?value)
}
但是,這里存在一個(gè)問(wèn)題:每當(dāng)你 Peek 項(xiàng)時(shí),都必須使用類型斷言將其從 interface{} 轉(zhuǎn)換為你需要的類型。如果你的堆棧是 *MyObject 的堆棧,則意味著很多 s.Peek().(*MyObject)這樣的代碼。這不僅讓人眼花繚亂,而且還可能引發(fā)錯(cuò)誤。比如忘記 * 怎么辦?或者如果您輸入錯(cuò)誤的類型怎么辦?s.Push(MyObject{})` 可以順利編譯,而且你可能不會(huì)發(fā)現(xiàn)到自己的錯(cuò)誤,直到它影響到你的整個(gè)服務(wù)為止。
通常,使用 interface{} 是相對(duì)危險(xiǎn)的。使用更多受限制的類型總是更安全,因?yàn)榭梢栽诰幾g時(shí)而不是運(yùn)行時(shí)發(fā)現(xiàn)問(wèn)題。
泛型通過(guò)允許類型具有類型參數(shù)來(lái)解決此問(wèn)題:
type?Stack(type?T)?[]Tfunc?(s?Stack(T))?Peek()?T?{
return?s[len(s)-1]
}
func?(s?*Stack(T))?Pop()?{
*s?=?(*s)[:
len(*s)-1]
}
func?(s?*Stack(T))?Push(value?T)?{
*s?=?
append(*s,?value)
}
這會(huì)向 Stack 添加一個(gè)類型參數(shù),從而完全不需要 interface{}?,F(xiàn)在,當(dāng)你使用 Peek() 時(shí),返回的值已經(jīng)是原始類型,并且沒有機(jī)會(huì)返回錯(cuò)誤的值類型。這種方式更安全,更容易使用。(譯注:就是看起來(lái)更丑陋,^-^)
此外,泛型代碼通常更易于編譯器優(yōu)化,從而獲得更好的性能(以二進(jìn)制大小為代價(jià))。如果我們對(duì)上面的非泛型代碼和泛型代碼進(jìn)行基準(zhǔn)測(cè)試,我們可以看到區(qū)別:
type?MyObject?struct?{
X?
int
}
var?sink?MyObjectfunc?BenchmarkGo1(b?*testing.B)?{
for?i?:=?0;?i??b.N;?i++?{
var?s?Stack
s.Push(MyObject{})
s.Push(MyObject{})
s.Pop()
sink?=?s.Peek().(MyObject)
}
}
func?BenchmarkGo2(b?*testing.B)?{
for?i?:=?0;?i??b.N;?i++?{
var?s?Stack(MyObject)
s.Push(MyObject{})
s.Push(MyObject{})
s.Pop()
sink?=?s.Peek()
}
}
結(jié)果:
BenchmarkGo1BenchmarkGo1-16?????12837528?????????87.0?ns/op???????48?B/op????????2?allocs/opBenchmarkGo2BenchmarkGo2-16?????28406479?????????41.9?ns/op???????24?B/op????????2?allocs/op
在這種情況下,我們分配更少的內(nèi)存,同時(shí)泛型的速度是非泛型的兩倍。
合約(Contracts)
上面的堆棧示例適用于任何類型。但是,在許多情況下,你需要編寫僅適用于具有某些特征的類型的代碼。例如,你可能希望堆棧要求類型實(shí)現(xiàn) String() 函數(shù)
不是為了與眾不同。而是為了更加清晰易懂。
Rob Pike 曾經(jīng)在 Go 官方博客解釋過(guò)這個(gè)問(wèn)題(原文地址:),簡(jiǎn)略翻譯如下(水平有限翻譯的不對(duì)的地方見諒):
引言
Go語(yǔ)言新人常常會(huì)很疑惑為什么這門語(yǔ)言的聲明語(yǔ)法(declaration syntax)會(huì)和傳統(tǒng)的C家族語(yǔ)言不同。在這篇博文里,我們會(huì)進(jìn)行一個(gè)比較,并做出解答。
C 的語(yǔ)法
首先,先看看 C 的語(yǔ)法。C 采用了一種聰明而不同尋常的聲明語(yǔ)法。聲明變量時(shí),只需寫出一個(gè)帶有目標(biāo)變量名的表達(dá)式,然后在表達(dá)式里指明該表達(dá)式本身的類型即可。比如:
int x;
上面的代碼聲明了 x 變量,并且其類型為 int——即,表達(dá)式 x 為 int 類型。一般而言,為了指明新變量的類型,我們得寫出一個(gè)表達(dá)式,其中含有我們要聲明的變量,這個(gè)表達(dá)式運(yùn)算的結(jié)果值屬于某種基本類型,我們把這種基本類型寫到表達(dá)式的左邊。所以,下述聲明:
int *p;
int a[3];
指明了 p 是一個(gè)int類型的指針,因?yàn)?*p 的類型為 int。而 a 是一個(gè) int 數(shù)組,因?yàn)?a[3] 的類型為 int(別管這里出現(xiàn)的索引值,它只是用于指明數(shù)組的長(zhǎng)度)。
我們接下來(lái)看看函數(shù)聲明的情況。C 的函數(shù)聲明中關(guān)于參數(shù)的類型是寫在括號(hào)外的,像下面這樣:
int main(argc, argv)
int argc;
char *argv[];
{ /* ... */ }
如前所述,我們可以看到 main 之所以是函數(shù),是因?yàn)楸磉_(dá)式 main(argc, argv) 返回 int。在現(xiàn)代記法中我們是這么寫的:
int main(int argc, char *argv[]) { /* ... */ }
盡管看起來(lái)有些不同,但是基本的結(jié)構(gòu)是一樣的。
總的來(lái)看,當(dāng)類型比較簡(jiǎn)單時(shí),C的語(yǔ)法顯得很聰明。但是遺憾的是一旦類型開始復(fù)雜,C的這套語(yǔ)法很快就能讓人迷糊了。著名的例子如函數(shù)指針,我們得按下面這樣來(lái)寫:
int (*fp)(int a, int b);
在這兒,fp 之所以是一個(gè)指針是因?yàn)槿绻銓懗?(*fp)(a, b) 這樣的表達(dá)式將會(huì)調(diào)用一個(gè)函數(shù),其返回 int 類型的值。如果當(dāng) fp 的某個(gè)參數(shù)本身又是一個(gè)函數(shù),情況會(huì)怎樣呢?
int (*fp)(int (*ff)(int x, int y), int b)
這讀起來(lái)可就點(diǎn)難了。
當(dāng)然了,我們聲明函數(shù)時(shí)是可以不寫明參數(shù)的名稱的,因此 main 函數(shù)可以聲明為:
int main(int, char *[])
回想一下,之前 argv 是下面這樣的
char *argv[]
你有沒有發(fā)現(xiàn)你是從聲明的「中間」去掉變量名而后構(gòu)造出其變量類型的?盡管這不是很明顯,但你聲明某個(gè) char *[] 類型的變量的時(shí)候,竟然需要把名字插入到變量類型的中間。
我們?cè)賮?lái)看看,如果我們不命名 fp 的參數(shù)會(huì)怎樣:
int (*fp)(int (*)(int, int), int)
這東西難懂的地方可不僅僅是要記得參數(shù)名原本是放這中間的
int (*)(int, int)
它更讓人混淆的地方還在于甚至可能都搞不清這竟然是個(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)需要指出,由于類型語(yǔ)法和聲明語(yǔ)法是一樣的,要解析中間帶有類型的表達(dá)式可能會(huì)有些難度。這也就是為什么,C 在做類型轉(zhuǎn)換的時(shí)候總是要把類型用括號(hào)括起來(lái)的原因,像這樣
(int)M_PI
Go 的語(yǔ)法
非C家族的語(yǔ)言通常在聲明時(shí)使用一種不同的類型語(yǔ)法。一般是名字先出現(xiàn),然后常常跟著一個(gè)冒號(hào)。按照這樣來(lái)寫,我們上面所舉的例子就會(huì)變成下面這樣:
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 的用法沒有直接的對(duì)應(yīng)關(guān)系(我們?cè)谙乱还?jié)會(huì)回過(guò)頭來(lái)探討指針的問(wèn)題)。至此,你獲得了代碼清晰性方面的提升,但付出的代價(jià)是語(yǔ)法上需要區(qū)別對(duì)待。
下面我們來(lái)考慮函數(shù)的問(wèn)題。雖然在 Go 語(yǔ)言里,main 函數(shù)實(shí)際上沒有參數(shù),但是我們先謄抄一下之前的 main 函數(shù)的聲明:
func main(argc int, argv *[]byte) int
粗略一看和 C 沒什么不同,不過(guò)自左向右讀的話還不錯(cuò)。
main 函數(shù)接受一個(gè) int 和一個(gè)指針并返回一個(gè) int。
如果此時(shí)把參數(shù)名去掉,它還是很清楚——因?yàn)閰?shù)名總在類型的前面,所以不會(huì)引起混淆。
func main(int, *[]byte) int
這種自左向右風(fēng)格的聲明的一個(gè)價(jià)值在于,當(dāng)類型變得更復(fù)雜時(shí),它依然相對(duì)簡(jiǎn)單。下面是一個(gè)函數(shù)變量的聲明(相當(dāng)于 C 語(yǔ)言里的函數(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)還是很清晰,自左向右,而且究竟哪一個(gè)變量名是當(dāng)前被聲明的也容易看懂——因?yàn)樽兞棵肋h(yuǎn)在首位。
類型語(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 的類型語(yǔ)法把方括號(hào)放在了類型的左邊,但是在表達(dá)式語(yǔ)法中卻又把方括號(hào)放到了右邊:
var a []int
x = a[1]
類似的,Go 的指針沿用了 C 的 * 記法,但是我們寫的時(shí)候也是聲明時(shí) * 在變量名右邊,但在表達(dá)式中卻又得把 * 放到左左邊:
var p *int
x = *p
不能寫成下面這樣
var p *int
x = p*
因?yàn)楹缶Y的 * 可能會(huì)和乘法運(yùn)算混淆,也許我們可以改用 Pascal 的 ^ 標(biāo)記,像這樣
var p ^int
x = p^
我們也許還真的應(yīng)該把 * 像上面這樣改成 ^ (當(dāng)然這么一改 xor 運(yùn)算的符號(hào)也得改),因?yàn)樵陬愋秃捅磉_(dá)式中的 * 前綴確實(shí)把好些事兒都搞得有點(diǎn)復(fù)雜,舉個(gè)例子來(lái)說(shuō),雖然我們可以像下面這樣寫
[]int("hi")
但在轉(zhuǎn)換時(shí),如果類型是以 * 開頭的,就得加上括號(hào):
(*int)(nil)
如果有一天我們?cè)敢夥艞売?* 作為指針語(yǔ)法的話,那么上面的括號(hào)就可以省略了。
可見,Go 的指針語(yǔ)法是和 C 相似的。但這種相似也意味著我們無(wú)法徹底避免在文法中有時(shí)為了避免類型和表達(dá)式的歧義需要補(bǔ)充括號(hào)的情況。
總而言之,盡管存在不足,但我們相信 Go 的類型語(yǔ)法要比 C 的容易懂。特別是當(dāng)類型比較復(fù)雜時(shí)。