下文章來(lái)源于大愚Talk ,作者大愚Talk
對(duì)于 Golang 語(yǔ)言應(yīng)用層面的知識(shí),先講如何正確的使用,然后再講它的實(shí)現(xiàn)。
Don't communicate by sharing memory, share memory by communicating.
相信寫過(guò) Go 的同學(xué)都知道這句名言,可以說(shuō) channel 就是后邊這句話的具體實(shí)現(xiàn)。我們來(lái)看一下到底 channel 是什么?
channel 是一個(gè)類型安全的隊(duì)列(循環(huán)隊(duì)列),能夠控制 groutine 在它上面讀寫消息的行為,比如:阻塞某個(gè) groutine ,或者喚醒某個(gè) groutine。
不同的 groutine 可以通過(guò) channel 交換任意的資源,由于 channel 能夠控制 groutine 的行為,所以 CSP 模型才能在 Golang 中順利實(shí)現(xiàn),它確保了不同 groutine 之間的數(shù)據(jù)同步機(jī)制。
上面的話是不是聽起來(lái)非常的不舒服?
好吧,簡(jiǎn)單說(shuō)人話就是,channel 是用來(lái)在 不同的 的 goroutine 中交換數(shù)據(jù)的。一定要注意這里 不同的 三個(gè)字。千萬(wàn)不要把 channel 拿來(lái)在不同函數(shù)(同一個(gè) goroutine 中)間交換數(shù)據(jù)。
知道了定義,我們來(lái)看具體如何使用。
如何定義一個(gè) channel 類型呢?
var ch1 chan int // 定義了一個(gè) int 類型的 channel,沒(méi)有初始化,是 nil
ch2 := make(chan int) // 定義+初始化了一個(gè)無(wú)緩沖的 int 類型 channel
ch3 := make(chan int) // 定義+初始化了一個(gè)有緩沖的 int 類型 channel
上面的定義方法我們都是定義的雙向通道,對(duì)應(yīng)的還有單向通道,但是單向通道我們一般只是做為函數(shù)參數(shù)來(lái)進(jìn)行一些限制,并不會(huì)在定義、初始化時(shí)就搞一個(gè)單向通道出來(lái)。因?yàn)槟愣x一個(gè)單向通道沒(méi)有任何實(shí)際價(jià)值,通道的存在本來(lái)就是用來(lái)交換數(shù)據(jù)的,單向通道只能滿足發(fā)或者收。
下面我們一起來(lái)看一下具體的使用,以及使用中注意的一些點(diǎn)。
不管是有緩沖的通道還是無(wú)緩沖的通道都是用來(lái)交換數(shù)據(jù)的,既然是交換數(shù)據(jù),無(wú)非就是寫入、讀取。我們先從發(fā)送開始。
ch := make(chan int)
defer close(ch)
//ch<-5 // 位置一
go func(ch chan int) {
num := <-ch
fmt.Println(num)
}(ch)
// ch<-5 // 位置二
如果我們打開 位置一 的注釋,程序是無(wú)法獲得預(yù)期執(zhí)行的,由于該 channel 是無(wú)緩沖的,位置一的代碼會(huì)陷入阻塞,下一行的 goroutine 根本沒(méi)有機(jī)會(huì)執(zhí)行。整個(gè)代碼會(huì)陷入死鎖。
正確的操作是,打開 位置二 的注釋,因?yàn)樯弦恍?goroutine 先行啟動(dòng),他是一個(gè)獨(dú)立的協(xié)程,不會(huì)阻塞主 groutine 的執(zhí)行。但它內(nèi)部會(huì)阻塞在 num :=<-ch 這行代碼,直到主協(xié)程執(zhí)行完 ch<-5 ,才會(huì)執(zhí)行打印。所以這里也有一個(gè)非常重要的問(wèn)題,主協(xié)程如果不等待子協(xié)程執(zhí)行完就退出的話,會(huì)看不到執(zhí)行結(jié)果。
這里先提一點(diǎn),無(wú)緩沖的 channel 并不會(huì)用到內(nèi)部結(jié)構(gòu)體的 buf ,這部分具體會(huì)在源碼部分講解他們的數(shù)據(jù)存取、交換的方式。
ch := make(chan int, 1) // 注意這里
defer close(ch)
//ch<-5 // 位置一
go func(ch chan int) {
num := <-ch
fmt.Println(num)
}(ch)
// ch<-5 // 位置二
代碼基本沒(méi)有改變,唯一的區(qū)別是 make 函數(shù)傳入了第二個(gè)參數(shù),這個(gè)值的含義是緩沖的大小。那么此時(shí) 位置一 與 位置二 都能夠正常執(zhí)行嗎?
答案是肯定的,此時(shí)的代碼,無(wú)論是那個(gè)位置,打開注釋后都能夠正常執(zhí)行。原因就在于由于 channel 有了緩存區(qū)域,位置一 寫入數(shù)據(jù)不會(huì)造成主協(xié)程的阻塞,那么下一行代碼的子協(xié)程就可以正常啟動(dòng),并直接將位置一寫入 buf 的數(shù)據(jù)讀取出來(lái)打印。
對(duì)于 位置二 ,由于子協(xié)程先啟動(dòng),但是會(huì)被阻塞在 num :=<-ch 這一行,因?yàn)榇藭r(shí) buf 中沒(méi)有任何內(nèi)容可讀?。ㄏ缕谠创a分析我們可以看代碼實(shí)現(xiàn)),直到位置二執(zhí)行完,喚醒子協(xié)程。
發(fā)送需要注意幾個(gè)問(wèn)題:
有寫入,必然后讀取。
還是上面的代碼, num :=<-ch 就是從 channel 讀取數(shù)據(jù)。對(duì)于讀取就不按照有緩沖與無(wú)緩沖來(lái)講解了,它們的主要問(wèn)題是什么時(shí)候阻塞。通過(guò)上面寫的例子自己再想想即可。
這里說(shuō)下讀取的兩種形式。
形式一
multi-valued assignment
v, ok := <-ch
ok 是一個(gè) bool 類型,可以通過(guò)它來(lái)判斷 channel 是否已經(jīng)關(guān)閉,如果關(guān)閉該值為 true ,此時(shí) v 接收到的是 channel 類型的零值。比如:channel 是傳遞的 int, 那么 v 就是 0 ;如果是結(jié)構(gòu)體,那么 v 就是結(jié)構(gòu)體內(nèi)部對(duì)應(yīng)字段的零值。
形式二
v := <-ch
該方式對(duì)于關(guān)閉的 channel 無(wú)法掌控,我們示例中就是該種方式。
接收需要注意幾個(gè)問(wèn)題:
對(duì)于 channel 的關(guān)閉,在什么地方去關(guān)閉呢?因?yàn)樯厦嬉仓v到向 closed 的 channel 寫或者繼續(xù) close 都會(huì)導(dǎo)致 panic問(wèn)題。
一般的建議是誰(shuí)寫入,誰(shuí)負(fù)責(zé)關(guān)閉。如果涉及到多個(gè)寫入的協(xié)程、多個(gè)讀取的協(xié)程?又該如何關(guān)閉?總的來(lái)說(shuō)就是加入一個(gè)標(biāo)記避免重復(fù)關(guān)閉。不過(guò)真的不建議搞的太復(fù)雜,否則后續(xù)維護(hù)代碼會(huì)瘋掉。
關(guān)閉需要注意幾個(gè)問(wèn)題:
我們常常會(huì)用 for-range 來(lái)讀取 channel的數(shù)據(jù)。
ch := make(chan int, 1)
go func(ch chan int) {
for i := 0; i < 10; i++ {
ch <- i
}
close(ch)
}(ch)
for val := range ch {
fmt.Println(val)
}
該語(yǔ)句的一個(gè)特色是如果 channel 已經(jīng)被關(guān)閉,它還是會(huì)繼續(xù)執(zhí)行,直到所有值被取完,然后退出執(zhí)行。而如果通道沒(méi)有關(guān)閉,但是channel沒(méi)有可讀取的數(shù)據(jù),它則會(huì)阻塞在 range 這句位置,直到被喚醒。但是如果 channel 是 nil,那么同樣符合我們上面說(shuō)的的原則,讀取會(huì)被阻塞,也就是會(huì)一直阻塞在 range位置。
select 是跟 channel 關(guān)系最親密的語(yǔ)句,它是被專門設(shè)計(jì)出來(lái)處理通道的,因?yàn)槊總€(gè) case 后面跟的都是通道表達(dá)式,可以是讀,也可以是寫。
ch := make(chan int)
q := make(chan int)
go func(ch, q chan int) {
for i := 0; i < 10; i++ {
num := <-ch
fmt.Println(num)
}
q <- 1
}(ch, q)
fibonacci := func(ch, q chan int) {
x, y := 0, 1
for {
select {
case ch <- x: // 寫入
x, y = y, x+y
break // 你覺(jué)得是否會(huì)影響 for 語(yǔ)句的循環(huán)?
case <-q: // 讀取
fmt.Println("quit")
return
}
}
}
fibonacci(ch, q)
上面的代碼是利用 channel 實(shí)現(xiàn)的一個(gè)斐波拉契數(shù)列。select 還可以有 default 語(yǔ)句,該語(yǔ)句會(huì)在其它 case 都被阻塞的情況下執(zhí)行。
關(guān)注的問(wèn)題
本文內(nèi)容很簡(jiǎn)單易懂,希望大家徹底掌握了 channel 的使用。一切源碼的研究都是為了更好的使用,后面的文章將開始研究 channel 的源碼實(shí)現(xiàn)。
本文幾個(gè)重要問(wèn)題再次總結(jié)下,也是經(jīng)常面試的??键c(diǎn)。
參考資料
o (計(jì)算機(jī)編程語(yǔ)言)
Go(又稱 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ì)算。
Go(又稱Golang)是Google開發(fā)的一種靜態(tài)強(qiáng)類型、編譯型、并發(fā)型,并具有垃圾回收功能的編程語(yǔ)言。
Python
Python是一種計(jì)算機(jī)程序設(shè)計(jì)語(yǔ)言。是一種面向?qū)ο蟮膭?dòng)態(tài)類型語(yǔ)言,最初被設(shè)計(jì)用于編寫自動(dòng)化腳本(shell),隨著版本的不斷更新和語(yǔ)言新功能的添加,越來(lái)越多被用于獨(dú)立的、大型項(xiàng)目的開發(fā)。
Python是一種解釋型腳本語(yǔ)言,可以應(yīng)用于以下領(lǐng)域:
1、Web 和 Internet開發(fā)
2、科學(xué)計(jì)算和統(tǒng)計(jì)
3、人工智能
4、教育
5、桌面界面開發(fā)
6、軟件開發(fā)
7、后端開發(fā)
優(yōu)點(diǎn)
簡(jiǎn)單:Python是一種代表簡(jiǎn)單主義思想的語(yǔ)言。閱讀一個(gè)良好的Python程序就感覺(jué)像是在讀英語(yǔ)一樣。它使你能夠?qū)W⒂诮鉀Q問(wèn)題而不是去搞明白語(yǔ)言本身。
易學(xué):Python極其容易上手,因?yàn)镻ython有極其簡(jiǎn)單的說(shuō)明文檔 。
速度快:Python 的底層是用 C 語(yǔ)言寫的,很多標(biāo)準(zhǔn)庫(kù)和第三方庫(kù)也都是用 C 寫的,運(yùn)行速度非常快。
免費(fèi)、開源:Python是FLOSS(自由/開放源碼軟件)之一。使用者可以自由地發(fā)布這個(gè)軟件的拷貝、閱讀它的源代碼、對(duì)它做改動(dòng)、把它的一部分用于新的自由軟件中。FLOSS是基于一個(gè)團(tuán)體分享知識(shí)的概念。
高層語(yǔ)言:用Python語(yǔ)言編寫程序的時(shí)候無(wú)需考慮諸如如何管理你的程序使用的內(nèi)存一類的底層細(xì)節(jié)。
可移植性:由于它的開源本質(zhì),Python已經(jīng)被移植在許多平臺(tái)上(經(jīng)過(guò)改動(dòng)使它能夠工作在不同平臺(tái)上)。這些平臺(tái)包括Linux、Windows、FreeBSD、Macintosh、Solaris、OS/2、Amiga、AROS、AS/400、BeOS、OS/390、z/OS、Palm OS、QNX、VMS、Psion、Acom RISC OS、VxWorks、PlayStation、Sharp Zaurus、Windows CE、PocketPC、Symbian以及Google基于linux開發(fā)的android平臺(tái)。
解釋性:一個(gè)用編譯性語(yǔ)言比如C或C++寫的程序可以從源文件(即C或C++語(yǔ)言)轉(zhuǎn)換到一個(gè)你的計(jì)算機(jī)使用的語(yǔ)言(二進(jìn)制代碼,即0和1)。這個(gè)過(guò)程通過(guò)編譯器和不同的標(biāo)記、選項(xiàng)完成。
運(yùn)行程序的時(shí)候,連接/轉(zhuǎn)載器軟件把你的程序從硬盤復(fù)制到內(nèi)存中并且運(yùn)行。而Python語(yǔ)言寫的程序不需要編譯成二進(jìn)制代碼。你可以直接從源代碼運(yùn)行 程序。
在計(jì)算機(jī)內(nèi)部,Python解釋器把源代碼轉(zhuǎn)換成稱為字節(jié)碼的中間形式,然后再把它翻譯成計(jì)算機(jī)使用的機(jī)器語(yǔ)言并運(yùn)行。這使得使用Python更加簡(jiǎn)單。也使得Python程序更加易于移植。
面向?qū)ο螅篜ython既支持面向過(guò)程的編程也支持面向?qū)ο蟮木幊?。在“面向過(guò)程”的語(yǔ)言中,程序是由過(guò)程或僅僅是可重用代碼的函數(shù)構(gòu)建起來(lái)的。在“面向?qū)ο蟆钡恼Z(yǔ)言中,程序是由數(shù)據(jù)和功能組合而成的對(duì)象構(gòu)建起來(lái)的。
可擴(kuò)展性:如果需要一段關(guān)鍵代碼運(yùn)行得更快或者希望某些算法不公開,可以部分程序用C或C++編寫,然后在Python程序中使用它們。
可嵌入性:可以把Python嵌入C/C++程序,從而向程序用戶提供腳本功能。
豐富的庫(kù):Python標(biāo)準(zhǔn)庫(kù)確實(shí)很龐大。它可以幫助處理各種工作,包括正則表達(dá)式、文檔生成、單元測(cè)試、線程、數(shù)據(jù)庫(kù)、網(wǎng)頁(yè)瀏覽器、CGI、FTP、電子郵件、XML、XML-RPC、HTML、WAV文件、密碼系統(tǒng)、GUI(圖形用戶界面)、Tk和其他與系統(tǒng)有關(guān)的操作。這被稱作Python的“功能齊全”理念。除了標(biāo)準(zhǔn)庫(kù)以外,還有許多其他高質(zhì)量的庫(kù),如wxPython、Twisted和Python圖像庫(kù)等等。
規(guī)范的代碼:Python采用強(qiáng)制縮進(jìn)的方式使得代碼具有較好可讀性。而Python語(yǔ)言寫的程序不需要編譯成二進(jìn)制代碼。
缺點(diǎn)
單行語(yǔ)句和命令行輸出問(wèn)題:很多時(shí)候不能將程序連寫成一行,如import sys;for i in sys.path:print i。而perl和awk就無(wú)此限制,可以較為方便的在shell下完成簡(jiǎn)單程序,不需要如Python一樣,必須將程序?qū)懭胍粋€(gè).py文件。
獨(dú)特的語(yǔ)法
這也許不應(yīng)該被稱為局限,但是它用縮進(jìn)來(lái)區(qū)分語(yǔ)句關(guān)系的方式還是給很多初學(xué)者帶來(lái)了困惑。即便是很有經(jīng)驗(yàn)的Python程序員,也可能陷入陷阱當(dāng)中。
運(yùn)行速度慢:這里是指與C和C++相比。
應(yīng)用
系統(tǒng)編程:提供API(Application Programming Interface應(yīng)用程序編程接口),能方便進(jìn)行系統(tǒng)維護(hù)和管理,Linux下標(biāo)志性語(yǔ)言之一,是很多系統(tǒng)管理員理想的編程工具。
圖形處理:有PIL、Tkinter等圖形庫(kù)支持,能方便進(jìn)行圖形處理。
數(shù)學(xué)處理:NumPy擴(kuò)展提供大量與許多標(biāo)準(zhǔn)數(shù)學(xué)庫(kù)的接口。
文本處理:python提供的re模塊能支持正則表達(dá)式,還提供SGML,XML分析模塊,許多程序員利用python進(jìn)行XML程序的開發(fā)。
數(shù)據(jù)庫(kù)編程:程序員可通過(guò)遵循Python DB-API(數(shù)據(jù)庫(kù)應(yīng)用程序編程接口)規(guī)范的模塊與Microsoft SQL Server,Oracle,Sybase,DB2,MySQL、SQLite等數(shù)據(jù)庫(kù)通信。python自帶有一個(gè)Gadfly模塊,提供了一個(gè)完整的SQL環(huán)境。
網(wǎng)絡(luò)編程:提供豐富的模塊支持sockets編程,能方便快速地開發(fā)分布式應(yīng)用程序。很多大規(guī)模軟件開發(fā)計(jì)劃例如Zope,Mnet 及BitTorrent. Google都在廣泛地使用它。
Web編程:應(yīng)用的開發(fā)語(yǔ)言,支持最新的XML技術(shù)。
多媒體應(yīng)用:Python的PyOpenGL模塊封裝了“OpenGL應(yīng)用程序編程接口”,能進(jìn)行二維和三維圖像處理。PyGame模塊可用于編寫游戲軟件。
pymo引擎:PYMO全稱為python memories off,是一款運(yùn)行于Symbian S60V3,Symbian3,S60V5, Symbian3, Android系統(tǒng)上的AVG游戲引擎。因其基于python2.0平臺(tái)開發(fā),并且適用于創(chuàng)建秋之回憶(memories off)風(fēng)格的AVG游戲,故命名為PYMO。
黑客編程:python有一個(gè)hack的庫(kù),內(nèi)置了你熟悉的或不熟悉的函數(shù),但是缺少成就感。
用Python寫簡(jiǎn)單爬蟲
首先,要通過(guò)urllib2這個(gè)Module獲得對(duì)應(yīng)的HTML源碼。(PS:在python3.3之后urllib2已經(jīng)不能再用,代之以u(píng)rllib)
1
2
3
4
import urllib2 #調(diào)用urllib2
url='http://www.baidu.com/s?wd=cloga' #把等號(hào)右邊的網(wǎng)址賦值給url
html=urllib2.urlopen(url).read() #html隨意取名 等號(hào)后面的動(dòng)作是打開源代碼頁(yè)面,并閱讀
print html #打印
通過(guò)上面這三句就可以將URL的源碼存在content變量中,其類型為字符型。
接下來(lái)是要從這堆HTML源碼中提取我們需要的內(nèi)容。用Chrome查看一下對(duì)應(yīng)的內(nèi)容的代碼(也可以用Firefox的Firebug)。
可以看到url的信息存儲(chǔ)在span標(biāo)簽中,要獲取其中的信息可以用正則式。
Go語(yǔ)言實(shí)戰(zhàn)》讀書筆記,未完待續(xù),第一時(shí)間看后續(xù)筆記。
對(duì)于協(xié)作開發(fā)或者代碼共享來(lái)說(shuō),文檔是一個(gè)可以幫助開發(fā)者快速了解以及使用這些代碼的一個(gè)教程,文檔越全面,越詳細(xì),入門越快,效率也會(huì)更高。
在Go語(yǔ)言中,Go為我們提供了快速生成文檔以及查看文檔的工具,讓我們可以很容易的編寫查看文檔。
Go提供了兩種查看文檔的方式,一種是使用go doc命令在終端查看,這種適用于使用VIM等工具在終端開發(fā)的人員,它們不用離開終端,既可以查看想查看的文檔,又可以編碼。
第二種方式,是使用瀏覽器查看的方式,通過(guò)godoc命令可以在本機(jī)啟動(dòng)一個(gè)web服務(wù),我們可以通過(guò)打開瀏覽器,訪問(wèn)這個(gè)服務(wù)來(lái)查看我們的Go文檔。
這種方式適用于在終端開發(fā)的,它們一般不像離開終端,查完即可繼續(xù)編碼,這時(shí)候使用go doc命令是很不錯(cuò)的選擇。
? hello go help doc
usage: go doc [-u] [-c] [package|[package.]symbol[.method]]
Doc prints the documentation comments associated with the item identified by its
arguments (a package, const, func, type, var, or method) followed by a one-line
summary of each of the first-level items "under" that item (package-level
declarations for a package, methods for a type, etc.).
Flags:
-c
Respect case when matching symbols.
-cmd
Treat a command (package main) like a regular package.
Otherwise package main's exported symbols are hidden
when showing the package's top-level documentation.
-u
Show documentation for unexported as well as exported
symbols and methods.
從以上可以看出,go doc的使用比較簡(jiǎn)單,接收的參數(shù)是包名,或者以包里的結(jié)構(gòu)圖、方法等。如果我們不輸入任何參數(shù),那么顯示的是當(dāng)前目錄的文檔,下面看個(gè)例子。
/*
提供的常用庫(kù),有一些常用的方法,方便使用
*/
package lib
// 一個(gè)加法實(shí)現(xiàn)
// 返回a+b的值
func Add(a,b int) int {
return a+b
}
? lib go doc
package lib // import "flysnow.org/hello/lib"
提供的常用庫(kù),有一些常用的方法,方便使用
func Add(a, b int) int
在當(dāng)前目錄執(zhí)行g(shù)o doc,輸出了當(dāng)前目錄下的文檔信息。
除此之外,我們還可以指定一個(gè)包,就可以列出當(dāng)前這個(gè)包的信息,著包括文檔、方法、結(jié)構(gòu)體等。
? lib go doc json
package json // import "encoding/json"
Package json implements encoding and decoding of JSON as defined in RFC
4627. The mapping between JSON and Go values is described in the
documentation for the Marshal and Unmarshal functions.
See "JSON and Go" for an introduction to this package:
https://golang.org/doc/articles/json_and_go.html
func Compact(dst *bytes.Buffer, src []byte) error
func HTMLEscape(dst *bytes.Buffer, src []byte)
func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error
func Marshal(v interface{}) ([]byte, error)
func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)
func Unmarshal(data []byte, v interface{}) error
type Decoder struct{ ... }
func NewDecoder(r io.Reader) *Decoder
type Delim rune
type Encoder struct{ ... }
func NewEncoder(w io.Writer) *Encoder
type InvalidUTF8Error struct{ ... }
type InvalidUnmarshalError struct{ ... }
type Marshaler interface{ ... }
type MarshalerError struct{ ... }
type Number string
type RawMessage []byte
type SyntaxError struct{ ... }
type Token interface{}
type UnmarshalFieldError struct{ ... }
type UnmarshalTypeError struct{ ... }
type Unmarshaler interface{ ... }
type UnsupportedTypeError struct{ ... }
type UnsupportedValueError struct{ ... }
以上是我們以json包為例,查看該包的文檔,從中我們可以看到它有一個(gè)名為Decoder的結(jié)構(gòu)體,我們進(jìn)一步查看這個(gè)結(jié)構(gòu)體的文檔。
? lib go doc json.Decoder
package json // import "encoding/json"
type Decoder struct {
// Has unexported fields.
}
A Decoder reads and decodes JSON values from an input stream.
func NewDecoder(r io.Reader) *Decoder
func (dec *Decoder) Buffered() io.Reader
func (dec *Decoder) Decode(v interface{}) error
func (dec *Decoder) More() bool
func (dec *Decoder) Token() (Token, error)
func (dec *Decoder) UseNumber()
現(xiàn)在我們看到這個(gè)Decoder有很多方法,進(jìn)一步查看這些方法的文檔,比如Decode。
? lib go doc json.Decoder.Decode
func (dec *Decoder) Decode(v interface{}) error
Decode reads the next JSON-encoded value from its input and stores it in the
value pointed to by v.
See the documentation for Unmarshal for details about the conversion of JSON
into a Go value.
go doc使用就是這樣,一步步,縮小范圍,查看想看的那些包、結(jié)構(gòu)體、接口或者函數(shù)方法的文檔。
go doc終端查看的方式,雖然也很便捷,不過(guò)效率不高,并且沒(méi)有查看細(xì)節(jié)以及進(jìn)行跳轉(zhuǎn),為此Go為我們提供了基于瀏覽器使用的網(wǎng)頁(yè)方式進(jìn)行瀏覽API 文檔,我們只用點(diǎn)點(diǎn)鼠標(biāo),就可以查看了,還可以在方法、包等之間進(jìn)行跳轉(zhuǎn),更簡(jiǎn)潔方便。
要想啟動(dòng)一個(gè)Web在線API文檔服務(wù)很簡(jiǎn)單,使用godoc就可以了。
? lib godoc -http=:6060
后面的http是要指定Web服務(wù)監(jiān)聽的IP和Port,運(yùn)行后,我們就可以打開瀏覽器,輸入http://127.0.0.1:6060進(jìn)行訪問(wèn)了,你會(huì)發(fā)現(xiàn)打開的頁(yè)面,和GoLang的官方網(wǎng)站一樣,沒(méi)錯(cuò),這個(gè)其實(shí)就是官網(wǎng)的一個(gè)拷貝,但是包的文檔http://127.0.0.1:6060/pkg/會(huì)和官網(wǎng)不一樣,你自己?jiǎn)?dòng)的這個(gè)服務(wù),是基于你電腦上GOROOT和GOPATH這兩個(gè)路徑下的所有包生成的文檔,會(huì)比官網(wǎng)只是標(biāo)準(zhǔn)庫(kù)的文檔要多。
在線瀏覽API文檔非常方便,只需要鼠標(biāo)點(diǎn)擊就可以了,也可以點(diǎn)擊藍(lán)色的超鏈接在方法、結(jié)構(gòu)、接口以及包等之間跳轉(zhuǎn),還可以查看對(duì)應(yīng)的源代碼,示例代碼,很方便,我們經(jīng)常用的也是這個(gè)在線瀏覽方式。
Go文檔工具,還有一個(gè)亮點(diǎn),就是可以支持開發(fā)人員自己寫的代碼,只要開發(fā)者按照一定的規(guī)則,就可以自動(dòng)生成文檔了。
在我們編碼中,文檔就是注釋,Go語(yǔ)言采用了和C、Java差不多的注釋風(fēng)格。一種是雙斜線的方式,一種是斜線和星號(hào)的方式。
/*
提供的常用庫(kù),有一些常用的方法,方便使用
*/
package lib
// 一個(gè)加法實(shí)現(xiàn)
// 返回a+b的值
func Add(a,b int) int {
return a+b
}
這還是我們剛剛那個(gè)例子,例子中文檔的編寫的兩種風(fēng)格。想要為哪些標(biāo)識(shí)符生車文檔,就在哪些標(biāo)識(shí)符之前,使用注釋的方式,加入到代碼中即可。
現(xiàn)在我們不管是用go doc,還是godoc都可以看到我們剛剛注釋的文檔了。
我們?cè)诳春芏喙俜紸PI文檔的時(shí)候,可以在文檔里看到一些例子,這些例子會(huì)告訴我們?cè)趺词褂肁PI,以及這個(gè)例子打印的輸出是什么,我覺(jué)得這個(gè)非常好,這樣看函數(shù)文檔看不懂的,可以參考這個(gè)例子,那么對(duì)于我們自己寫的API,怎么給API文檔添加示例代碼呢?
這里我參考了官方的源代碼,總結(jié)了測(cè)試了一下,發(fā)現(xiàn)可行,這里分享一下。
說(shuō)了這三個(gè)規(guī)則,下面通過(guò)一個(gè)例子更直觀的了解。
package lib
import "fmt"
func Example() {
sum:=Add(1,2)
fmt.Println("1+2=",sum)
//Output:
//1+2=3
}
這就是為剛剛那個(gè)Add函數(shù)寫的示例代碼,我們運(yùn)行g(shù)odoc就可以看到結(jié)果了。
Go的文檔工具非常強(qiáng)大,更多功能,我們可以使用幫助命令查看。這里再推薦一個(gè)比較不錯(cuò)的第三方的API文檔網(wǎng)站,收錄了包括官方在內(nèi)的很多Go庫(kù),可以直接跳轉(zhuǎn),關(guān)聯(lián)源代碼,非常方便。https://gowalker.org/
《Go語(yǔ)言實(shí)戰(zhàn)》讀書筆記,未完待續(xù),第一時(shí)間看后續(xù)筆記。
*請(qǐng)認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。