<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          作為Gopher,你知道Go的注釋即文檔應(yīng)該怎么寫嗎?

          共 6603字,需瀏覽 14分鐘

           ·

          2022-04-10 13:49


          導(dǎo)語?|?Go一直奉行“注釋即文檔”的概念,在代碼中針對(duì)各種public內(nèi)容進(jìn)行注釋之后,這些注釋也就是對(duì)應(yīng)內(nèi)容的文檔,這稱為GoDoc。那么作為gopher,你知道GoDoc應(yīng)該怎么寫嗎?


          引言


          剛?cè)腴TGo開發(fā)時(shí),在開源項(xiàng)目的主頁上我們經(jīng)??梢钥吹竭@樣的一個(gè)徽章:



          點(diǎn)擊徽章,就可以打開https://pkg.go.dev/的網(wǎng)頁,網(wǎng)頁中給出了這個(gè)開源項(xiàng)目所對(duì)應(yīng)的Go文檔。在剛接觸Go的時(shí)候,我曾一度以為,pkg.go.dev上面的文檔是需要開發(fā)者上傳并審核的——要不然那些文檔咋都顯得那么專業(yè)呢。


          然而當(dāng)我寫自己的輪子時(shí),慢慢的我就發(fā)現(xiàn)并非如此。


          劃重點(diǎn):在pkg.go.dev上的文檔,都是Go自動(dòng)從開源項(xiàng)目的工程代碼中爬取、格式化后展現(xiàn)出來的。換句話說,每個(gè)人都可以寫自己的GoDoc并且展示在pkg.go.dev上,只需要遵從GoDoc的格式標(biāo)準(zhǔn)即可,也不需要任何審核動(dòng)作。


          本文章的目的是通過例子,簡(jiǎn)要說明GoDoc的格式,讓讀者也可以自己寫一段高大上的godoc。以下內(nèi)容以我自己的jsonvalue(https://github.com/Andrew-M-C/go.jsonvalue)包為例子。其對(duì)應(yīng)的GoDoc在這里(https://pkg.go.dev/github.com/Andrew-M-C/go.jsonvalue)。讀者可以點(diǎn)開,并與代碼中的內(nèi)容做參考對(duì)比。



          一、什么是GoDoc


          顧名思義,GoDoc就是Go語言的文檔。在實(shí)際應(yīng)用中,godoc可能可以指以下含義:


          • 在2019年11月之前,表示https://godoc.org中的內(nèi)容。


          • 現(xiàn)在godoc.org已經(jīng)下線,會(huì)重定向到pkg.go.dev,并且其功能也都重新遷移到這上面——下文以“pkg.go.dev”指代這個(gè)含義。


          • Go開發(fā)工具的一個(gè)命令,就叫做godoc——下文直接以“godoc”指代這個(gè)工具。


          • pkg.go.dev的相關(guān)命令,被叫做pkgsite,代碼托管在GitHub上——下文以“pkgsite”指代這個(gè)工具。


          • Go工具包的文檔以及生成該文檔所相關(guān)的格式——下文以“GoDoc”指代這個(gè)含義。


          目前的godoc和pkgsite有兩個(gè)作用,一個(gè)是用來本地調(diào)試自己的GoDoc顯示效果;另一個(gè)是在無法科學(xué)上網(wǎng)的時(shí)候,用來本地搭建GoDoc服務(wù)器之用。



          二、godoc命令


          我們從工具命令開始講起吧。在2019年之前,Go使用的是godoc這個(gè)工具來格式化和展示Go代碼中自帶的文檔。現(xiàn)在這個(gè)命令已經(jīng)不再包含于Go工具鏈中,而需要額外安裝:


          go get -v golang.org/x/tools/cmd/godoc


          godoc命令有多種模式和參數(shù),這里我們列出最常用和最簡(jiǎn)便的模式:


          cd XXXX; godoc -http=:6060


          其中XXXX是包含go.mod的一個(gè)倉庫目錄。假設(shè)XXX是我的jsonvalue(https://github.com/Andrew-M-C/go.jsonvalue)庫的本地目錄,根據(jù)go.mod,這個(gè)庫的地址是github.com/Andrew-M-C/go.jsonvalue,那么我就可以在瀏覽器中打開http://${IP}:${PORT}/pkg/github.com/Andrew-M-C/go.jsonvalue/,就可以訪問我的jsonvalue庫的GoDoc頁面了,如下圖所示:




          三、pkgsite命令


          正如前文所說,現(xiàn)在Go官方維護(hù)和使用的是pkg.go.dev,因此本文主要說明pkgsite的用法。


          當(dāng)前的pkgsite要求Go 1.18版,因此請(qǐng)把Go版升級(jí)到1.18。然后我們需要安裝pkgsite:


          go install golang.org/x/pkgsite/cmd/pkgsite@latest


          然后和godoc類似:


          cd XXXX; pkgsite -http=:6060


          一樣用jsonvalue舉例。瀏覽器的地址與godoc類似,但是少了“pkg/”,頁面如下圖所示:




          四、pkg.go.dev內(nèi)容


          (一)總體內(nèi)容


          由于筆者在jsonvalue中對(duì)GoDoc玩得比較多,因此還是以這個(gè)庫為例子。我們打開pkg.go.dev中相關(guān)包的主頁,可以看到這些內(nèi)容:



          A-當(dāng)前package的完整路徑。


          B-當(dāng)前package的名稱,其中的module表示這是一個(gè)符合go module的包。


          C-當(dāng)前package的一些基礎(chǔ)信息,包括最新版本、發(fā)布時(shí)間、證書、依賴的包數(shù)量(包括系統(tǒng)包)、被引用的包數(shù)量。


          D-如果當(dāng)前package包含README文件,則展示README文件的內(nèi)容。


          E-當(dāng)前package內(nèi)的comment as document文檔內(nèi)容。


          F-當(dāng)前package的文件列表,可以點(diǎn)擊快速瀏覽。


          G-當(dāng)前package的子目錄列表。


          如果你的README (markdown格式) 有子標(biāo)題,那么pkgsite會(huì)生成 README 下的二級(jí)目錄索引。Markdown的格式在本文就不予說明,相信碼農(nóng)們都耳熟能詳了。



          (二)Documentation


          讓我們點(diǎn)開Documentation,一個(gè)完整的package,可能包含以下這些內(nèi)容:




          其實(shí)Documentation的內(nèi)容,就是GoDoc。Go秉承“注釋即文檔”的理念,其中pkg.go.dev、godoc和pkgsite都使用同一套GoDoc格式,三者都按照該格式從文檔的注釋中提取,并生成文檔。


          下面我們具體來說明一下GoDoc的語法。



          五、GoDoc語法

          ??????????


          在GoDoc中,當(dāng)前package的所有可導(dǎo)出類型,都會(huì)在pkg.go.dev頁面中展示出來,即便某個(gè)可導(dǎo)出類型沒有任何的注釋,GoDoc也會(huì)將這個(gè)可導(dǎo)出內(nèi)容的原型展示出來——當(dāng)然了,我們應(yīng)該時(shí)時(shí)刻刻記住:所有的可導(dǎo)出內(nèi)容,都應(yīng)該寫好注釋。


          GoDoc支持//和/* ... */兩種模式的注釋符。但是筆者還是推薦使用//,這也是目前的注釋符主流,而且大部分IDE也都支持一鍵將多行文本直接轉(zhuǎn)為注釋(比如Mac的VsCode,使用command+/)。雖然/* */在多行注釋中非常方便,但一旦看到這個(gè),總覺得好像是上古時(shí)代的代碼 (狗頭)。


          (一)綁定GoDoc與指定類型


          對(duì)于任意一個(gè)可導(dǎo)出內(nèi)容,緊跟著代碼定義上方一行的注釋,都會(huì)被視為該內(nèi)容的GoDoc,從而被提取出來。比如說:


          // 這一行,會(huì)被視為 SomeTypeA 的 GoDoc,// 因?yàn)樗o挨著 SomeTypeA 的定義。type SomeTypeA struct{}
          // 這一行與 SomeTypeB 的定義之間隔了一行,// 所以并不會(huì)認(rèn)為是 SomeTypeB 的 GoDoc。
          type SomeTypeB struct{}
          /*使用這種注釋符的注釋也是同理,因?yàn)檎麄€(gè)注釋塊緊挨著 SomeTypeC 的定義,因此會(huì)被視為 SomeTypeC 的注釋。*/type SomeTypeC struct{}


          這三個(gè)類型在pkgsite頁面上的展示效果是這樣的:



          但是,請(qǐng)讀者注意,按照Go官方的推薦,代碼注釋的第一個(gè)單詞,應(yīng)該是被注釋的內(nèi)容本身。比如前文中,SomeTypeA的注釋應(yīng)該是// SomeTypeA開頭。下文開始將會(huì)統(tǒng)一使用這一規(guī)范。



          (二)換行(段落)


          讀者可以注意到,前文中的所有有效注釋,我都換了一行;但是在pkgsite的頁面展示中,并沒有發(fā)生換行。


          實(shí)際上,在注釋中如果只是單純的一個(gè)換行另寫注釋的話,在頁面是不會(huì)將其當(dāng)作新的一段來看待的,GoDoc的邏輯,也僅僅渲染完這一行之后,再加一個(gè)空格,然后繼續(xù)渲染下一行。


          如果要在同一個(gè)注釋塊中新加一個(gè)段落,那么我們需要插入一行空注釋,如下:


          // SomeNewLine 只是用來展示如何在 GoDoc 中換行。//// 你看,這就是新的一行了,耶~??func SomeNewLine() error {    return nil}




          (三)內(nèi)嵌代碼


          如果有需要的話,我們可以在注釋中內(nèi)嵌一小段代碼,代碼會(huì)被獨(dú)立為一個(gè)段落,并且使用等寬字符展示。比如下面的一個(gè)例子:


          // IntsElem 用于不 panic 地從一個(gè) int 切片中讀取元素,并且返回值和實(shí)際在切片中的位置。//// 不論是任何情況,如果切片長(zhǎng)為0,則 actual Index 返回 -1.//// 根據(jù)參數(shù) index 可以有幾種情況://// - 零值,則直接取切片的第一個(gè)值//// - 正值,則從切片0位置開始,如果遇到切片結(jié)束了,那么就循環(huán)從頭開始數(shù)//// - 負(fù)值,則表示逆序,此時(shí)則循環(huán)從切片的最后一個(gè)值開始數(shù)//// 負(fù)值的例子:////    sli := []int{0, -1, -2, -3}//    val, idx := IntsElem(sli, -2)//// 返回得 val = -2, idx = 2func IntsElem(ints []int, index int) (value, actualIndex int) {    // ......}



          總結(jié):在注釋塊中,如果部分注釋行符合以下標(biāo)準(zhǔn)之一,則視為代碼塊:


          • 注釋行以制表符\t開頭。


          • 注釋行以以多于一個(gè)空格(包括制表符)開頭。


          普通注釋和代碼塊之間可以不用專門的空注釋行,但個(gè)人建議還是加上比較好。



          六、Overview部分


          在Documentation中的Overview部分,是整個(gè)package的說明,這種類型的注釋,被稱為“包注釋”。包注釋是寫在go文件最開始的package xxx上面。雖然GoDoc沒有限制、但是Go官方建議包注釋應(yīng)當(dāng)以// Package xxx開頭作為文本的主語。


          如果在一個(gè)package中,有多個(gè)文件都包含了包注釋,那么GoDoc會(huì)按照文件的字典序,依次展示這些文件中的包注釋。但這樣可能會(huì)帶來混亂,因此一個(gè)package我們應(yīng)當(dāng)只在一個(gè)文件中寫包注釋。


          一般而言,我們可以選擇以下的文件寫包注釋:


          • 很多package下面會(huì)有一個(gè)與package名稱同名的xxx.go文件,那我們可以統(tǒng)一就在這個(gè)文件里寫包注釋,比如這樣:(https://github.com/Andrew-M-C/go.jsonvalue/blob/v1.2.0/jsonvalue.go#L1)


          • 如果xxx.go文件本身承載了較多代碼,或者是包注釋比較長(zhǎng),那么我們可以專門開一個(gè)doc.go文件,用來寫包注釋,比如這樣:(https://github.com/Andrew-M-C/go.jsonvalue/blob/v1.0.0/doc.go#L1)



          七、棄用代碼聲明


          Go所使用的版本號(hào)是vX.Y.Z的模式,按照官方的思想,每當(dāng)package升級(jí)時(shí),盡量不要升級(jí)大版本X值,這也同時(shí)代表著,本次升級(jí)是完全向前兼容的。但是實(shí)際上,我們?cè)谧鲆恍┬“姹净蛑邪姹旧?jí)時(shí),有些函數(shù)/類型可能不再推薦使用。此時(shí),GoDoc提供了一個(gè)關(guān)鍵字Deprecated:,作為整個(gè)注釋塊的第一個(gè)單詞,比如我們可以這么寫:


          // Deprecated: ElemAt 這個(gè)函數(shù)棄用,后續(xù)請(qǐng)遷移到 IntsElem 函數(shù)中.func ElemAt(ints []int, index int) int {    // ......}


          針對(duì)deprecated的內(nèi)容,pkgsite一方面會(huì)在目錄中標(biāo)識(shí)出來:



          此外,在正文中,也會(huì)刻意用灰色字體低調(diào)展示,并且隱藏注釋正文,需要點(diǎn)開才能顯示:





          八、代碼示例文檔


          讀者如果看我jsonvalue的文檔(https://pkg.go.dev/github.com/Andrew-M-C/go.jsonvalue#Set.At),在At()函數(shù)下,除了上文提到的文檔正文之外,還有五個(gè)代碼示例:


          那么,文檔中的代碼示例又應(yīng)該如何寫呢?


          首先,我們應(yīng)該新建至少一個(gè)文件,專門用來存放示例代碼。比如我就把示例代碼寫在了example_jsonvalue_test.go(https://github.com/Andrew-M-C/go.jsonvalue/blob/master/example_jsonvalue_test.go)文件中。這個(gè)文件的package名不得與當(dāng)前包名相同,而應(yīng)該命名為包名_test的格式。


          此外,需要注意的是,示例代碼文件也屬于單元測(cè)試文件的內(nèi)容,當(dāng)執(zhí)行g(shù)o test的時(shí)候,示例文件也會(huì)納入測(cè)試邏輯中。


          (一)示例代碼的聲明


          如何聲明一個(gè)示例代碼,這里我舉兩個(gè)例子。首先是在At()函數(shù)下名為“Example (1)”的示例。在代碼(https://github.com/Andrew-M-C/go.jsonvalue/blob/master/example_jsonvalue_test.go#L112)中,我把這個(gè)函數(shù)命名為:


          func ExampleSet_At_1() {    ......}


          這個(gè)函數(shù)命名有幾個(gè)部分:



          另外,示例代碼中應(yīng)該包含標(biāo)準(zhǔn)輸出內(nèi)容,這樣便于讀者了解執(zhí)行情況。標(biāo)準(zhǔn)輸出內(nèi)容在函數(shù)內(nèi)的最后,采用//Output:?單獨(dú)起一行開頭,剩下的每一行標(biāo)準(zhǔn)輸出寫一行注釋。


          相對(duì)應(yīng)地,如果你想要給(不屬于任何一個(gè)類型的)函數(shù)寫示例的話,則去掉上文中關(guān)于“類型”的字段;如果你不需要示例的額外說明符,則去掉“額外說明”字段。比如說,我給類型Opt寫的示例(https://pkg.go.dev/github.com/Andrew-M-C/go.jsonvalue#example-Opt)就只有一個(gè),在代碼(https://github.com/Andrew-M-C/go.jsonvalue/blob/master/example_jsonvalue_test.go#L43)中,只有一行:


          func ExampleOpt() {    ........}


          甚至連示例說明都沒有。


          如果一個(gè)元素包含多個(gè)例子,那么godoc會(huì)按照字母序?qū)κ纠捌湎鄳?yīng)的說明排序。這也就是為什么我干脆在At()函數(shù)中,示例標(biāo)為一二三四五的原因,因?yàn)檫@是我希望讀者閱讀示例的順序。



          (二)在官網(wǎng)上發(fā)布GoDoc


          好了,當(dāng)你寫好了自己的GoDoc之后,總不是自己看自己自娛自樂吧,總歸是要發(fā)布出來給大家看的。


          其實(shí)發(fā)布也很簡(jiǎn)單:當(dāng)你將包含了godoc的代碼push之后(比如發(fā)布到github上),就可以在瀏覽器中輸入https://pkg.go.dev/${package路徑名}。比如jsonvalue的Github路徑(也等同于import路徑)為github.com/Andrew-M-C/go.jsonvalue,因此輸入(https://pkg.go.dev/github.com/Andrew-M-C/go.jsonvalue)。


          如果這是該頁面第一次進(jìn)入,那么pkg.go.dev會(huì)首先獲取、解析和更新代碼倉庫中的文檔內(nèi)容,并且格式化之后展示。在pkg.go.dev中,如果能夠找到package的最新的tag版本,那么會(huì)列出tag(而不是主干分支)上的GoDoc。


          接下來更重要的是,把這份官網(wǎng)GoDoc的鏈接,附到你自己的README中。我們可以進(jìn)入pkg.go.dev的徽章生成頁(????????https://pkg.go.dev/badge/?)


          輸入倉庫地址就可以看到相應(yīng)的徽標(biāo)的鏈接了。有html和markdown格式任君選擇。



          參考資料:

          1.萬字長(zhǎng)文解讀pkg.go.dev的設(shè)計(jì)和實(shí)現(xiàn)

          2.pkg.go.dev源碼


          (?轉(zhuǎn)載須取得作者同意,未經(jīng)許可,禁止二次轉(zhuǎn)載?)



          ?作者簡(jiǎn)介


          張敏

          騰訊高級(jí)后臺(tái)工程師

          騰訊高級(jí)后臺(tái)工程師,在電子和互聯(lián)網(wǎng)行業(yè)深耕多年,擁有豐富的嵌入式和云服務(wù)后臺(tái)開發(fā)經(jīng)驗(yàn),個(gè)人博客共有過百篇文章,云+社區(qū)Top50原創(chuàng)作者,技術(shù)創(chuàng)作101第二季講師,現(xiàn)負(fù)責(zé)騰訊產(chǎn)品后臺(tái)開發(fā)。



          ?推薦閱讀


          技術(shù)的發(fā)展,如何高效助力行業(yè)數(shù)字化?

          從中心走向邊緣——解讀邊緣計(jì)算解決方案!

          并發(fā)編程,為什么選Go?

          再不Go就來不及了!Go高性能編程技法解讀



          ??閱讀原文前往「騰訊云+社區(qū)」作者個(gè)人主頁參與交流哦~

          瀏覽 37
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  蜜桃臀美女被操 | 77777亚洲熟妇 | 国产又黄又爽的免费视频 | 黄片网站在线播放 | 免费作爱视频 |