目前主流的幾種語(yǔ)言有java、C、C++、Basic、PHP、C#、Python、java等語(yǔ)言。我推薦你學(xué)習(xí)java、C、C++C#這四門語(yǔ)言。如果你是初學(xué)者的話,并且打算深入研究的話。我推薦你先學(xué)習(xí)C與C++,不過在初期階段C相對(duì)簡(jiǎn)單些。然后,我個(gè)人認(rèn)為這兩門語(yǔ)言可以全部學(xué)習(xí),因?yàn)樗鼈冊(cè)诤芏嗟胤绞窍嗤ǖ?,這兩門語(yǔ)言可以讓你對(duì)整個(gè)計(jì)算機(jī)學(xué)提供一些認(rèn)知,即使其他的語(yǔ)言上,C與C++提供的知識(shí)也十分有幫助。然后你可以接著學(xué)java,java語(yǔ)言的適用范圍十分廣泛,但相較于其他入門語(yǔ)言它略顯復(fù)雜,所以一般是在學(xué)習(xí)完C或C++后進(jìn)行學(xué)習(xí)。
創(chuàng)新互聯(lián)服務(wù)項(xiàng)目包括斗門網(wǎng)站建設(shè)、斗門網(wǎng)站制作、斗門網(wǎng)頁(yè)制作以及斗門網(wǎng)絡(luò)營(yíng)銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢(shì)、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,斗門網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到斗門省份的部分城市,未來相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!
如果你不打算深入了解的話,你可以直接學(xué)習(xí)python語(yǔ)言,python語(yǔ)言你可以理解為DIY,學(xué)習(xí)完之后可以很快制作自己的程序。
單純數(shù)據(jù)運(yùn)算的話,Go語(yǔ)言執(zhí)行效率要跟高于PHP. Go語(yǔ)言更偏向于工程學(xué),體積大, 邏輯簡(jiǎn)單, 有一定運(yùn)算量, 不適合處理業(yè)務(wù). php適合做邏輯.
常見的計(jì)算機(jī)編程語(yǔ)言有:
編程語(yǔ)言一、C語(yǔ)言
C語(yǔ)言是世界上最流行、使用最廣泛的高級(jí)程序設(shè)計(jì)語(yǔ)言之一。在操作系統(tǒng)和系統(tǒng)使用程序以及需要對(duì)硬件進(jìn)行操作的場(chǎng)合,用C語(yǔ)言明顯優(yōu)于其它高級(jí)語(yǔ)言,許多大型應(yīng)用軟件都是用C語(yǔ)言編寫的。
C語(yǔ)言繪圖能力強(qiáng),具有可移植性,并具備很強(qiáng)的數(shù)據(jù)處理能力,因此適于編寫系統(tǒng)軟件,三維,二維圖形和動(dòng)畫。它是數(shù)值計(jì)算的高級(jí)語(yǔ)言。
編程語(yǔ)言二、java
Java是一種可以撰寫跨平臺(tái)應(yīng)用軟件的面向?qū)ο蟮某绦蛟O(shè)計(jì)語(yǔ)言,是由Sun Microsystems公司于1995年5月推出的Java程序設(shè)計(jì)語(yǔ)言和Java平臺(tái)(即JavaSE, JavaEE, JavaME)的總稱。Java 技術(shù)具有卓越的通用性、高效性、平臺(tái)移植性和安全性,廣泛應(yīng)用于個(gè)人PC、數(shù)據(jù)中心、游戲控制臺(tái)、科學(xué)超級(jí)計(jì)算機(jī)、移動(dòng)電話和互聯(lián)網(wǎng),同時(shí)擁有全球最大的開發(fā)者專業(yè)社群。
編程語(yǔ)言三、c++
C++這個(gè)詞在中國(guó)大陸的程序員圈子中通常被讀做“C加加”,而西方的程序員通常讀做“C plus plus”,“CPP”。 它是一種使用非常廣泛的計(jì)算機(jī)編程語(yǔ)言。C++是一種靜態(tài)數(shù)據(jù)類型檢查的、支持多重編程范式的通用程序設(shè)計(jì)語(yǔ)言。它支持過程化程序設(shè)計(jì)、數(shù)據(jù)抽象、面向?qū)ο蟪绦蛟O(shè)計(jì)、泛型程序設(shè)計(jì)等多種程序設(shè)計(jì)風(fēng)格。
編程語(yǔ)言四、php
PHP,是英文超文本預(yù)處理語(yǔ)言Hypertext Preprocessor的縮寫。PHP 是一種 HTML 內(nèi)嵌式的語(yǔ)言,是一種在服務(wù)器端執(zhí)行的嵌入HTML文檔的腳本語(yǔ)言,語(yǔ)言的風(fēng)格有類似于C語(yǔ)言,被廣泛地運(yùn)用。用PHP做出的動(dòng)態(tài)頁(yè)面與其他的編程語(yǔ)言相比,PHP是將程序嵌入到HTML文檔中去執(zhí)行,執(zhí)行效率比完全生成HTML標(biāo)記的CGI要高許多;PHP還可以執(zhí)行編譯后代碼,編譯可以達(dá)到加密和優(yōu)化代碼運(yùn)行,使代碼運(yùn)行更快。(php公益培訓(xùn))
編程語(yǔ)言五、c#
C#是微軟公司發(fā)布的一種面向?qū)ο蟮?、運(yùn)行于.NET Framework之上的高級(jí)程序設(shè)計(jì)語(yǔ)言。并定于在微軟職業(yè)開發(fā)者論壇(PDC)上登臺(tái)亮相。C#是微軟公司研究員Anders Hejlsberg的最新成果。C#看起來與Java有著驚人的相似;它包括了諸如單一繼承、接口、與Java幾乎同樣的語(yǔ)法和編譯成中間代碼再運(yùn)行的過程。
前言
最近工作中遇到的一個(gè)場(chǎng)景,php項(xiàng)目中需要使用一個(gè)第三方的功能,而恰好有一個(gè)用Golang寫好的類庫(kù)。那么問題就來了,要如何實(shí)現(xiàn)不同語(yǔ)言之間的通信呢?下面就來一起看看吧。
常規(guī)的方案
1、 用Golang寫一個(gè)http/TCP服務(wù),php通過http/TCP與Golang通信
2、將Golang經(jīng)過較多封裝,做為php擴(kuò)展。
3、PHP通過系統(tǒng)命令,調(diào)取Golang的可執(zhí)行文件
存在的問題
1、http請(qǐng)求,網(wǎng)絡(luò)I/O將會(huì)消耗大量時(shí)間
2、需要封裝大量代碼
3、PHP每調(diào)取一次Golang程序,就需要一次初始化,時(shí)間消耗很多
優(yōu)化目標(biāo)
1、Golang程序只初始化一次(因?yàn)槌跏蓟芎臅r(shí))
2、所有請(qǐng)求不需要走網(wǎng)絡(luò)
3、盡量不大量修改代碼
解決方案
1、簡(jiǎn)單的Golang封裝,將第三方類庫(kù)編譯生成為一個(gè)可執(zhí)行文件
2、PHP與Golang通過雙向管道通信
使用雙向管道通信優(yōu)勢(shì)
1:只需要對(duì)原有Golang類庫(kù)進(jìn)行很少的封裝
2:性能最佳 (IPC通信是進(jìn)程間通信的最佳途徑)
3:不需要走網(wǎng)絡(luò)請(qǐng)求,節(jié)約大量時(shí)間
4:程序只需初始化一次,并一直保持在內(nèi)存中
具體實(shí)現(xiàn)步驟
1:類庫(kù)中的原始調(diào)取demo
package main
import (
"fmt"
"github.com/yanyiwu/gojieba"
"strings"
)
func main() {
x := gojieba.NewJieba()
defer x.Free()
s := "小明碩士畢業(yè)于中國(guó)科學(xué)院計(jì)算所,后在日本京都大學(xué)深造"
words := x.CutForSearch(s, true)
fmt.Println(strings.Join(words, "/"))
}
保存文件為main.go,就可以運(yùn)行
2:調(diào)整后代碼為:
package main
import (
"bufio"
"fmt"
"github.com/yanyiwu/gojieba"
"io"
"os"
"strings"
)
func main() {
x := gojieba.NewJieba(
"/data/tmp/jiebaDict/jieba.dict.utf8",
"/data/tmp/jiebaDict/hmm_model.utf8",
"/data/tmp/jiebaDict/user.dict.utf8"
)
defer x.Free()
inputReader := bufio.NewReader(os.Stdin)
for {
s, err := inputReader.ReadString('\n')
if err != nil err == io.EOF {
break
}
s = strings.TrimSpace(s)
if s != "" {
words := x.CutForSearch(s, true)
fmt.Println(strings.Join(words, " "))
} else {
fmt.Println("get empty \n")
}
}
}
只需要簡(jiǎn)單的幾行調(diào)整,即可實(shí)現(xiàn):從標(biāo)準(zhǔn)輸入接收字符串,經(jīng)過分詞再輸出
測(cè)試:
# go build test
# ./test
# //等待用戶輸入,輸入”這是一個(gè)測(cè)試“
# 這是 一個(gè) 測(cè)試 //程序
3:使用cat與Golang通信做簡(jiǎn)單測(cè)試
//準(zhǔn)備一個(gè)title.txt,每行是一句文本
# cat title.txt | ./test
正常輸出,表示cat已經(jīng)可以和Golang正常交互了
4:PHP與Golang通信
以上所示的cat與Golang通信,使用的是單向管道。即:只能從cat向Golang傳入數(shù)據(jù),Golang輸出的數(shù)據(jù)并沒有傳回給cat,而是直接輸出到屏幕。但文中的需求是:php與Golang通信。即php要傳數(shù)據(jù)給Golang,同時(shí)Golang也必須把執(zhí)行結(jié)果返回給php。因此,需要引入雙向管道。
在PHP中管道的使用:popen("/path/test") ,具體就不展開說了,因?yàn)榇朔椒ń鉀Q不了文中的問題。
雙向管道:
$descriptorspec = array(
0 = array("pipe", "r"),
1 = array("pipe", "w")
);
$handle = proc_open(
'/webroot/go/src/test/test',
$descriptorspec,
$pipes
);
fwrite($pipes['0'], "這是一個(gè)測(cè)試文本\n");
echo fgets($pipes[1]);
解釋:使用proc_open打開一個(gè)進(jìn)程,調(diào)用Golang程序。同時(shí)返回一個(gè)雙向管道pipes數(shù)組,php向$pipe['0']中寫數(shù)據(jù),從$pipe['1']中讀數(shù)據(jù)。
好吧,也許你已經(jīng)發(fā)現(xiàn),我是標(biāo)題檔,這里重點(diǎn)要講的并不只是PHP與Golang如何通信。而是在介紹一種方法: 通過雙向管道讓任意語(yǔ)言通信。(所有語(yǔ)言都會(huì)實(shí)現(xiàn)管道相關(guān)內(nèi)容)
測(cè)試:
通過對(duì)比測(cè)試,計(jì)算出各個(gè)流程占用的時(shí)間。下面提到的title.txt文件,包含100萬(wàn)行文本,每行文本是從b2b平臺(tái)取的商品標(biāo)題
1: 整體流程耗時(shí)
time cat title.txt | ./test /dev/null
耗時(shí):14.819秒,消耗時(shí)間包含:
進(jìn)程cat讀出文本
通過管道將數(shù)據(jù)傳入Golang
Golang處理數(shù)據(jù),將結(jié)果返回到屏幕
2:計(jì)算分詞函數(shù)耗時(shí)。方案:去除分詞函數(shù)的調(diào)取,即:注釋掉Golang源代碼中的調(diào)取分詞那行的代碼
time cat title.txt | ./test /dev/null
耗時(shí):1.817秒時(shí)間,消耗時(shí)間包含:
進(jìn)程cat讀出文本
通過管道將數(shù)據(jù)傳入Golang
Golang處理數(shù)據(jù),將結(jié)果返回到屏幕
分詞耗時(shí) = (第一步耗時(shí)) - (以上命令所耗時(shí))
分詞耗時(shí) : 14.819 - 1.817 = 13.002秒
3:測(cè)試cat進(jìn)程與Golang進(jìn)程之間通信所占時(shí)間
time cat title.txt /dev/null
耗時(shí):0.015秒,消耗時(shí)間包含:
進(jìn)程cat讀出文本
通過管道將數(shù)據(jù)傳入Golang
go處理數(shù)據(jù),將結(jié)果返回到屏幕
管道通信耗時(shí):(第二步耗時(shí)) - (第三步耗時(shí))
管道通信耗時(shí): 1.817 - 0.015 = 1.802秒
4:PHP與Golang通信的時(shí)間消耗
編寫簡(jiǎn)單的php文件:
?php
$descriptorspec = array(
0 = array("pipe", "r"),
1 = array("pipe", "w")
);
$handle = proc_open(
'/webroot/go/src/test/test',
$descriptorspec,
$pipes
);
$fp = fopen("title.txt", "rb");
while (!feof($fp)) {
fwrite($pipes['0'], trim(fgets($fp))."\n");
echo fgets($pipes[1]);
}
fclose($pipes['0']);
fclose($pipes['1']);
proc_close($handle);
流程與上面基本一致,讀出title.txt內(nèi)容,通過雙向管道傳入Golang進(jìn)程分詞后,再返回給php (比上面的測(cè)試多一步:數(shù)據(jù)再通過管道返回)
time php popen.php /dev/null
耗時(shí):24.037秒,消耗時(shí)間包含:
進(jìn)程PHP讀出文本
通過管道將數(shù)據(jù)傳入Golang
Golang處理數(shù)據(jù)
Golang將返回結(jié)果再寫入管道,PHP通過管道接收數(shù)據(jù)
將結(jié)果返回到屏幕
結(jié)論:
1 :整個(gè)分詞過程中的耗時(shí)分布
使用cat控制邏輯耗時(shí): 14.819 秒
使用PHP控制邏輯耗時(shí): 24.037 秒(比cat多一次管道通信)
單向管道通信耗時(shí): 1.8 秒
Golang中的分詞函數(shù)耗時(shí): 13.002 秒
2:分詞函數(shù)的性能: 單進(jìn)程,100萬(wàn)商品標(biāo)題分詞,耗時(shí)13秒
以上時(shí)間只包括分詞時(shí)間,不包括詞典載入時(shí)間。但在本方案中,詞典只載入一次,所以載入詞典時(shí)間可以忽略(1秒左右)
3:PHP比cat慢 (這結(jié)論有點(diǎn)多余了,呵呵)
語(yǔ)言層面慢: (24.037 - 1.8 - 14.819) / 14.819 = 50%
單進(jìn)程對(duì)比測(cè)試的話,應(yīng)該不會(huì)有哪個(gè)語(yǔ)言比cat更快。
相關(guān)問題:
1:以上Golang源碼中寫的是一個(gè)循環(huán),也就是會(huì)一直從管道中讀數(shù)據(jù)。那么存在一個(gè)問題:是不是php進(jìn)程結(jié)束后,Golang的進(jìn)程還會(huì)一直存在?
管道機(jī)制自身可解決此問題。管道提供兩個(gè)接口:讀、寫。當(dāng)寫進(jìn)程結(jié)束或者意外掛掉時(shí),讀進(jìn)程也會(huì)報(bào)錯(cuò),以上Golang源代碼中的err邏輯就會(huì)執(zhí)行,Golang進(jìn)程結(jié)束。
但如果PHP進(jìn)程沒有結(jié)束,只是暫時(shí)沒有數(shù)據(jù)傳入,此時(shí)Golang進(jìn)程會(huì)一直等待。直到php結(jié)束后,Golang進(jìn)程才會(huì)自動(dòng)結(jié)束。
2:能否多個(gè)php進(jìn)程并行讀寫同一個(gè)管道,Golang進(jìn)程同時(shí)為其服務(wù)?
不可以。管道是單向的,如果多個(gè)進(jìn)程同時(shí)向管道中寫,那Golang的返回值就會(huì)錯(cuò)亂。
可以多開幾個(gè)Golang進(jìn)程實(shí)現(xiàn),每個(gè)php進(jìn)程對(duì)應(yīng)一個(gè)Golang進(jìn)程。
最后,上面都是瞎扯的。如果你了解管道、雙向管道,上面的解釋對(duì)你基本沒啥用。但如果你不了解管道,調(diào)試上面的代碼沒問題,但稍有修改就有可能掉坑里。
首頁(yè)你需要開啟apache服務(wù)器
然后把你要運(yùn)行的文件放入apache的根目錄
你如果安裝在C盤的話,就是在這個(gè)文件夾下C:\wamp\www
還有你要是有數(shù)據(jù)的話,打開apache后將數(shù)據(jù)導(dǎo)入到數(shù)據(jù)庫(kù)中
———文章來源 YamiOdymel/PHP-to-Golang
PHP和模塊之間的關(guān)系令人感到煩躁,假設(shè)你要讀取 yaml 檔案,你需要有一個(gè) yaml 的模塊,為此,你還需要將其編譯然后將編譯后的模塊擺放至指定位置,之后換了一臺(tái)伺服器你還要重新編譯,這點(diǎn)到現(xiàn)在還是沒有改善;順帶一提之后出了PHP 7效能確實(shí)提升了許多(比Python 3快了些),但PHP仍令我感到臃腫,我覺得是時(shí)候
(轉(zhuǎn)行)了。
PHP 和Golang 的效能我想毋庸置疑是后者比較快(而且是以倍數(shù)來算),也許有的人會(huì)認(rèn)為兩種不應(yīng)該被放在一起比較,但Golang 本身就是偏向Web 開發(fā)的,所以這也是為什么我考慮轉(zhuǎn)用Golang 的原因,起初我的考慮有幾個(gè):Node.js 和Rust 還有最終被選定的Golang;先談?wù)凬ode.js 吧。
Node.js的效能可以說是快上PHP 3.5倍至6倍左右 ,而且撰寫的語(yǔ)言還是JavaScript,蒸蚌,如此一來就不需要學(xué)習(xí)新語(yǔ)言了!搭配Babel更可以說是萬(wàn)能,不過那跟「跳跳虎」一樣的Async邏輯還有那恐怖的Callback Hell,有人認(rèn)為前者是種優(yōu)點(diǎn),這點(diǎn)我不否認(rèn),但是對(duì)學(xué)習(xí)PHP的我來說太過于"Mind Fuck",至于后者的Callback Hell雖然有Promise,但是那又是另一個(gè)「Then Hell」的故事了。相較于Golang之下,Node.js似乎就沒有那么吸引我了。你確實(shí)可以用Node.js寫出很多東西,不過那V8引擎的效能仍然有限,而且要學(xué)習(xí)新的事物,不就應(yīng)該是「全新」的嗎;)?
題外話: 為什么Node.js不適合大型和商業(yè)專案?
在拋棄改用Node.js 之后我曾經(jīng)花了一天的時(shí)間嘗試Rust 和Iron 框架,嗯??Rust 太強(qiáng)大了,強(qiáng)大到讓我覺得Rust 不應(yīng)該用在這里,這想法也許很蠢,但Rust 讓我覺得適合更應(yīng)該拿來用在系統(tǒng)或者是部分底層的地方,而不應(yīng)該是網(wǎng)路服務(wù)。
Golang是我最終的選擇,主要在于我花了一天的時(shí)間來研究的時(shí)候意外地發(fā)現(xiàn)Golang夭壽簡(jiǎn)潔( 關(guān)鍵字只有25個(gè) ),相較之下Rust太過于「強(qiáng)大」令我怯步;而且Golang帶有許多工具,例如 go fmt 會(huì)自動(dòng)幫你整理程式碼、 go doc 會(huì)自動(dòng)幫你生產(chǎn)文件、 go test 可以自動(dòng)單元測(cè)試并生產(chǎn)覆蓋率報(bào)表、也有 go get 套件管理工具(雖然沒有版本功能),不過都很實(shí)用,而且也不需要加上分號(hào)( ; ),真要說不好的地方??大概就是強(qiáng)迫你花括號(hào)不能換行放吧(沒錯(cuò),我就是花括號(hào)會(huì)換行放的人)。
當(dāng)我在撰寫這份文件的時(shí)候 我會(huì)先假設(shè)你有一定的基礎(chǔ) ,你可以先閱讀下列的手冊(cè),他們都很不錯(cuò)。
你能夠在PHP 里面想建立一個(gè)變數(shù)的時(shí)候就直接建立,夭壽贊,是嗎?
蒸蚌!那么Golang 呢?在Golang 中變數(shù)分為幾類:「新定義」、「預(yù)先定義」、「自動(dòng)新定義」、「覆蓋」。讓我們來看看范例:
在PHP中你會(huì)很常用到 echo 來顯示文字,像這樣。
然而在Golang中你會(huì)需要 fmt 套件,關(guān)于「什么是套件」的說明你可以在文章下述了解。
這很簡(jiǎn)單,而且兩個(gè)語(yǔ)言的用法相差甚少,下面這是PHP:
只是Golang 稍微聒噪了一點(diǎn),你必須在函式后面宣告他最后會(huì)回傳什么資料型別。
在PHP 中你要回傳多個(gè)資料你就會(huì)用上陣列,然后將資料放入陣列里面,像這樣。
然而在Golang 中你可以不必用到一個(gè)陣列,函式可以一次回傳多個(gè)值:
兩個(gè)語(yǔ)言的撰寫方式不盡相同。
主要是PHP 的陣列能做太多事情了,所以在PHP 里面要儲(chǔ)存什么用陣列就好了。
在Golang里??沒有這么萬(wàn)能的東西,首先要先了解Golang中有這些型態(tài): array , slice , map , interface ,
你他媽的我到底看了三洨,首先你要知道Golang是個(gè)強(qiáng)型別語(yǔ)言,意思是你的陣列中 只能有一種型態(tài) ,什么意思?當(dāng)你決定這個(gè)陣列是用來擺放字串資料的時(shí)候,你就只能在里面放字串。沒有數(shù)值、沒有布林值,就像你沒有女朋友一樣。
先撇開PHP 的「萬(wàn)能陣列」不管,Golang 中的陣列既單純卻又十分腦殘,在定義一個(gè)陣列的時(shí)候,你必須給他一個(gè)長(zhǎng)度還有其內(nèi)容存放的資料型態(tài),你的陣列內(nèi)容不一定要填滿其長(zhǎng)度,但是你的陣列內(nèi)容不能超過你當(dāng)初定義的長(zhǎng)度。
切片??這聽起來也許很奇怪,但是你確實(shí)可以「切」他,讓我們先談?wù)劇盖衅贡绕稹戈嚵小挂迷谀睦铮骸改悴挥枚x其最大長(zhǎng)度,而且你可以直接賦予值」,沒了。
我們剛才有提到你可以「切」他,記得嗎?這有點(diǎn)像是PHP中的 array_slice() ,但是Golang直接讓Slice「內(nèi)建」了這個(gè)用法,其用法是: slice[開始:結(jié)束] 。
在PHP中倒是沒有那么方便,在下列PHP范例中你需要不斷地使用 array_slice() 。
你可以把「映照」看成是一個(gè)有鍵名和鍵值的陣列,但是記住:「你需要事先定義其鍵名、鍵值的資料型態(tài)」,這仍限制你沒辦法在映照中存放多種不同型態(tài)的資料。
在Golang里可就沒這么簡(jiǎn)單了,你需要先用 make() 宣告 map 。
也許你不喜歡「接口」這個(gè)詞,但用「介面」我怕會(huì)誤導(dǎo)大眾,所以,是的,接下來我會(huì)繼續(xù)稱其為「接口」。還記得你可以在PHP 的關(guān)聯(lián)陣列里面存放任何型態(tài)的資料嗎,像下面這樣?
現(xiàn)在你有福了!正因?yàn)镚olang中的 interface{} 可以接受任何內(nèi)容,所以你可以把它拿來存放任何型態(tài)的資料。
有時(shí)候你也許會(huì)有個(gè)不定值的變數(shù),在PHP 里你可以直接將一個(gè)變數(shù)定義成字串、數(shù)值、空值、就像你那變心的女友一樣隨時(shí)都在變。
在Golang中你必須給予變數(shù)一個(gè)指定的資料型別,不過還記得剛才提到的:「Golang中有個(gè) interface{} 能夠 存放任何事物 」嗎( 雖然也不是真的任何事物啦?? )?
當(dāng)我們程式中不需要繼續(xù)使用到某個(gè)資源或是發(fā)生錯(cuò)誤的時(shí)候,我們索性會(huì)將其關(guān)閉或是拋棄來節(jié)省資源開銷,例如PHP 里的讀取檔案:
在Golang中,你可以使用 defer 來在函式結(jié)束的時(shí)候自動(dòng)執(zhí)行某些程式(其執(zhí)行方向?yàn)榉聪?。所以你就不需要在函式最后面結(jié)束最前面的資源。
defer 可以被稱為「推遲執(zhí)行」,實(shí)際上就是在函式結(jié)束后會(huì)「反序」執(zhí)行的東西,例如你按照了這樣的順序定義 defer : A-B-C-D ,那么執(zhí)行的順序其實(shí)會(huì)是 D-C-B-A ,這用在程式結(jié)束時(shí)還蠻有用的,讓我們看看Golang如何改善上述范例。
這東西很邪惡,不是嗎?又不是在寫B(tài)ASIC,不過也許有時(shí)候你會(huì)在PHP 用上呢。但是拜托,不要。
Golang中僅有 for 一種回圈但卻能夠達(dá)成 foreach 、 while 、 for 多種用法。普通 for 回圈寫法在兩個(gè)語(yǔ)言中都十分相近。
在Golang請(qǐng)記得:如果你的 i 先前并不存在,那么你就需要定義它,所以下面這個(gè)范例你會(huì)看見 i := 0 。
在PHP里, foreach() 能夠直接給你值和鍵名,用起來十分簡(jiǎn)單。
Golang里面雖然僅有 for() 但卻可以使用 range 達(dá)成和PHP一樣的 foreach 方式。
一個(gè) while(條件) 回圈在PHP里面可以不斷地執(zhí)行區(qū)塊中的程式,直到 條件 為 false 為止。
在Golang里也有相同的做法,但仍是透過 for 回圈,請(qǐng)注意這個(gè) for 回圈并沒有任何的分號(hào)( ; ),而且一個(gè)沒有條件的 for 回圈會(huì)一直被執(zhí)行。
PHP中有 do .. while() 回圈可以先做區(qū)塊中的動(dòng)作。
在Golang中則沒有相關(guān)函式,但是你可以透過一個(gè)無(wú)止盡的 for 回圈加上條件式來讓他結(jié)束回圈。
要是你真的希望完全符合像是PHP那樣的設(shè)計(jì)方式,或者你可以在Golang中使用很邪惡的 goto 。
在PHP中我們可以透過 date() 像這樣取得目前的日期。
在Golang就稍微有趣點(diǎn)了,因?yàn)镚olang中并不是以 Y-m-d 這種格式做為定義,而是 1 、 2 、 3 ,這令你需要去翻閱文件,才能夠知道 1 的定義是代表什么。
俗話說:「爆炸就是藝術(shù)」,可愛的PHP用詞真的很大膽,像是: explode() (爆炸)、 die() (死掉),回歸正傳,如果你想在PHP里面將字串切割成陣列,你可以這么做。
簡(jiǎn)單的就讓一個(gè)字串給「爆炸」了,那么Golang 呢?
對(duì)了,記得引用 strings 套件。
這真的是很常用到的功能,就像物件一樣有著鍵名和鍵值,在PHP 里面你很簡(jiǎn)單的就能靠陣列(Array)辦到。
真是太棒了,那么Golang呢?用 map 是差不多啦。如果有必要的話,你可以稍微復(fù)習(xí)一下先前提到的「多資料儲(chǔ)存型態(tài)-Stores」。
你很常會(huì)在PHP里面用 isset() 檢查一個(gè)索引是否存在,不是嗎?
在Golang里面很簡(jiǎn)單的能夠這樣辦到(僅適用于 map )。
指針(有時(shí)也做參照)是一個(gè)像是「變數(shù)別名」的方法,這種方法讓你不用整天覆蓋舊的變數(shù),讓我們假設(shè) A = 1; B = A; 這個(gè)時(shí)候 B 會(huì)復(fù)制一份 A 且兩者不相干,倘若你希望修改 B 的時(shí)候?qū)嶋H上也會(huì)修改到 A 的值,就會(huì)需要指針。
指針比起復(fù)制一個(gè)變數(shù),他會(huì)建立一個(gè)指向到某個(gè)變數(shù)的記憶體位置,這也就是為什么你改變指針,實(shí)際上是在改變某個(gè)變數(shù)。
在Golang你需要用上 * 還有 符號(hào)。
有些時(shí)候你會(huì)回傳一個(gè)陣列,這個(gè)陣列里面可能有資料還有錯(cuò)誤代號(hào),而你會(huì)用條件式判斷錯(cuò)誤代號(hào)是否非空值。
在Golang中函式可以一次回傳多個(gè)值。為此,你不需要真的回傳一個(gè)陣列,不過要注意的是你將會(huì)回傳一個(gè)屬于 error 資料型態(tài)的錯(cuò)誤,所以你需要引用 errors 套件來幫助你做這件事。
該注意的是Golang沒有 try .. catch ,因?yàn)?Golang推薦這種錯(cuò)誤處理方式 ,你應(yīng)該在每一次執(zhí)行可能會(huì)發(fā)生錯(cuò)誤的程式時(shí)就處理錯(cuò)誤,而非后來用 try 到處包覆你的程式。
在 if 條件式里宣告變數(shù)會(huì)讓你只能在 if 內(nèi)部使用這個(gè)變數(shù),而不會(huì)污染到全域范圍。
也許你在PHP中更常用的會(huì)是 try .. catch ,在大型商業(yè)邏輯時(shí)經(jīng)常看見如此地用法,實(shí)際上這種用法令人感到聒噪(因?yàn)槟銜?huì)需要一堆 try 區(qū)塊):
Golang中并沒有 try .. catch ,實(shí)際上Golang也 不鼓勵(lì)這種行為 (Golang推薦逐一處理錯(cuò)誤的方式),倘若你真想辦倒像是捕捉異常這樣的方式,你確實(shí)可以使用Golang中另類處理錯(cuò)誤的方式(可以的話盡量避免使用這種方式): panic() , recover() , defer 。
你可以把 panic() 當(dāng)作是 throw (丟出錯(cuò)誤),而這跟PHP的 exit() 有87%像,一但你執(zhí)行了 panic() 你的程式就會(huì)宣告而終,但是別擔(dān)心,因?yàn)槌淌浇Y(jié)束的時(shí)候會(huì)呼叫 defer ,所以我們接下來要在 defer 停止 panic() 。
關(guān)于 defer 上述已經(jīng)有提到了,他是一個(gè)反向執(zhí)行的宣告,會(huì)在函式結(jié)束后被執(zhí)行,當(dāng)你呼叫了 panic() 結(jié)束程式的時(shí)候,也就會(huì)開始執(zhí)行 defer ,所以我們要在 defer 內(nèi)使用 recover() 讓程式不再繼續(xù)進(jìn)行結(jié)束動(dòng)作,這就像是捕捉異常。
recover() 可以看作 catch (捕捉),我們要在 defer 里面用 recover() 解決 panic() ,如此一來程式就會(huì)回歸正常而不會(huì)被結(jié)束。
還記得在PHP里要引用一堆檔案的日子嗎?到處可見的 require() 或是 include() ?到了Golang這些都不見了,取而代之的是「套件(Package)」?,F(xiàn)在讓我們來用PHP解釋一下。
這看起來很正常對(duì)吧?但假設(shè)你有一堆檔案,這馬上就成了 Include Hell ,讓我們看看Golang怎么透過「套件」解決這個(gè)問題。
「 蛤???殺????? 」你可能如此地說道。是的, main.go 中除了引用 fmt 套件( 為了要輸出結(jié)果用的套件 )之外完全沒有引用到 a.go 。
「 蛤???殺?。?????? 」你仿佛回到了幾秒鐘前的自己。
既然沒有引用其他檔案,為什么 main.go 可以輸出 foo 呢?注意到了嗎, 兩者都是屬于 main 套件 ,因此 他們共享同一個(gè)區(qū)域 ,所以接下來要介紹的是什么叫做「套件」。
套件是每一個(gè) .go 檔案都必須聲明在Golang原始碼中最開端的東西,像下面這樣:
這意味著目前的檔案是屬于 main 套件( 你也可以依照你的喜好命名 ),那么要如何讓同個(gè)套件之間的函式溝通呢?
接著是Golang;注意!你不需要引用任何檔案,因?yàn)橄铝袃蓚€(gè)檔案同屬一個(gè)套件。
一個(gè)由「套件」所掌握的世界,比起PHP的 include() 和 require() 還要好太多了,對(duì)嗎?
在Golang 中沒有引用單獨(dú)檔案的方式,你必須匯入一整個(gè)套件,而且你要記?。骸敢欢銋R入了,你就一定要使用它」,像下面這樣。
假如你不希望使用你匯入的套件,你只是為了要觸發(fā)那個(gè)套件的 main() 函式而引用的話??,那么你可以在前面加上一個(gè)底線( _ )。
如果你的套件出現(xiàn)了名稱沖突,你可以在套件來源前面給他一個(gè)新的名稱。
現(xiàn)在你知道可以匯入套件了,那么什么是「匯出」?同個(gè)套件內(nèi)的函式還有共享變數(shù)確實(shí)可以直接用,但那 并不表示可以給其他套件使用 ,其方法取決于 函式/變數(shù)的「開頭大小寫」 。
是的。 Golang依照一個(gè)函式/變數(shù)的開頭大小寫決定這個(gè)東西是否可供「匯出」 。
這用在區(qū)別函式的時(shí)候格外有用,因?yàn)樾戦_頭的任何事物都是不供匯出的,反之,大寫開頭的任何事物都是用來匯出供其他套件使用的。
一開始可能會(huì)覺得這是什么奇異的規(guī)定,但寫久之后,你就能發(fā)現(xiàn)比起JavaScript和Python以「底線為開頭的命名方式」還要來得更好;比起成天宣告 public 、 private 、 protected 還要來得更快。
在Golang 中沒有類別,但有所謂的「建構(gòu)體(Struct)」和「接口(Interface)」,這就能夠滿足幾乎所有的需求了,這也是為什么我認(rèn)為Golang 很簡(jiǎn)潔卻又很強(qiáng)大的原因。
讓我們先用PHP 建立一個(gè)類別,然后看看Golang 怎么解決這個(gè)問題。
雖然Golang沒有類別,但是「建構(gòu)體(Struct)」就十分地堪用了,首先你要知道在Golang中「類別」的成員還有方法都是在「類別」外面所定義的,這跟PHP在類別內(nèi)定義的方式有所不同,在Golang中還有一點(diǎn),那就是他們沒有 public 、 private 、 protected 的種類。
在PHP中,當(dāng)有一個(gè)類別被 new 的時(shí)候會(huì)自動(dòng)執(zhí)行該類別內(nèi)的建構(gòu)子( __construct() ),通常你會(huì)用這個(gè)來初始化一些類別內(nèi)部的值。
但是在Golang 里因?yàn)闆]有類別,也就沒有建構(gòu)子,不巧的是建構(gòu)體本身也不帶有建構(gòu)子的特性,這個(gè)時(shí)候你只能自己在外部建立一個(gè)建構(gòu)用函式。
讓我們假設(shè)你有兩個(gè)類別,你會(huì)把其中一個(gè)類別傳入到另一個(gè)類別里面使用,廢話不多說!先上個(gè)PHP 范例(為了簡(jiǎn)短篇幅我省去了換行)。
在Golang中你也有相同的用法,但是請(qǐng)記得:「 任何東西都是在「類別」外完成建構(gòu)的 」。
在PHP 中沒有相關(guān)的范例,這部分會(huì)以剛才「嵌入」章節(jié)中的Golang 范例作為解說對(duì)象。
你可以看見Golang在進(jìn)行 Foo 嵌入 Bar 的時(shí)候,會(huì)自動(dòng)將 Foo 的成員暴露在 Bar 底下,那么假設(shè)「雙方之間有相同的成員名稱」呢?
這個(gè)時(shí)候被嵌入的成員就會(huì)被「遮蔽」,下面是個(gè)實(shí)際范例,還有你如何解決遮蔽問題:
雖然都是呼叫同一個(gè)函式,但是這個(gè)函式可以針對(duì)不同的資料來源做出不同的舉動(dòng),這就是多形。你也能夠把這看作是:「訊息的意義由接收者定義,而不是傳送者」。
目前PHP 中沒有真正的「多形」,不過你仍可以做出同樣的東西。
嗯??那么Golang呢?實(shí)際上更簡(jiǎn)單而且更有條理了,在Golang中有 interface 可以幫忙完成這個(gè)工作。
如果你對(duì)Interface還不熟悉,可以試著查看「 解釋Golang中的Interface到底是什么 」文章。
謝謝你看到這里,可惜這篇文章卻沒有說出Golang 最重要的賣點(diǎn):「Goroutine」和「Channel」