婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av

主頁 > 知識庫 > 模塊一 GO語言基礎(chǔ)知識-庫源碼文件

模塊一 GO語言基礎(chǔ)知識-庫源碼文件

熱門標(biāo)簽:地圖標(biāo)注免費定制店 上海極信防封電銷卡價格 宿遷便宜外呼系統(tǒng)代理商 不封卡外呼系統(tǒng) 重慶慶云企業(yè)400電話到哪申請 仙桃400電話辦理 湛江crm外呼系統(tǒng)排名 寧波語音外呼系統(tǒng)公司 鄭州智能語音電銷機器人價格

你已經(jīng)使用過 Go 語言編寫了小命令(或者說微型程序)嗎?

當(dāng)你在編寫“Hello, world”的時候,一個源碼文件就足夠了,雖然這種小玩意兒沒什么用,最多能給你一點點莫名的成就感。如果你對這一點點并不滿足,別著急,跟著學(xué),我肯定你也可以寫出很厲害的程序。

我們在上一篇的文章中學(xué)到了命令源碼文件的相關(guān)知識,那么除了命令源碼文件,你還能用 Go 語言編寫庫源碼文件。那么什么是庫源碼文件呢?

在我的定義中,庫源碼文件是不能被直接運行的源碼文件,它僅用于存放程序?qū)嶓w,這些程序?qū)嶓w可以被其他代碼使用(只要遵從 Go 語言規(guī)范的話)。

這里的“其他代碼”可以與被使用的程序?qū)嶓w在同一個源碼文件內(nèi),也可以在其他源碼文件,甚至其他代碼包中。

那么程序?qū)嶓w是什么呢?在 Go 語言中,程序?qū)嶓w是變量、常量、函數(shù)、結(jié)構(gòu)體和接口的統(tǒng)稱。我們總是會先聲明(或者說定義)程序?qū)嶓w,然后再去使用。比如在上一篇的例子中,我們先定義了變量name,然后在main函數(shù)中調(diào)用fmt.Printf函數(shù)的時候用到了它。再多說一點,程序?qū)嶓w的名字被統(tǒng)稱為標(biāo)識符。標(biāo)識符可以是任何 Unicode 編碼可以表示的字母字符、數(shù)字以及下劃線“_”,但是其首字母不能是數(shù)字。從規(guī)則上說,我們可以用中文作為變量的名字。但是,我覺得這種命名方式非常不好,自己也會在開發(fā)團隊中明令禁止這種做法。作為一名合格的程序員,我們應(yīng)該向著編寫國際水準(zhǔn)的程序無限逼近。

回到正題。

我們今天的問題是:怎樣把命令源碼文件中的代碼拆分到其他庫源碼文件?

我們用代碼演示,把這個問題說得更具體一些。

如果在某個目錄下有一個命令源碼文件 demo4.go,如下:

package main
 
import (
 "flag"
)
 
var name string
 
func init() {
 flag.StringVar(name, "name", "everyone", "The greeting object.")
}
 
func main() {
 flag.Parse()
 hello(name)
}

其中的代碼你應(yīng)該比較眼熟了。我在講命令源碼文件的時候貼過很相似的代碼,那個源碼文件名為 demo2.go。

這兩個文件的不同之處在于,demo2.go 直接通過調(diào)用fmt.Printf函數(shù)打印問候語,而當(dāng)前的 demo4.go 在同樣位置調(diào)用了一個叫作hello的函數(shù)。

函數(shù)hello被聲明在了另外一個源碼文件中,我把它命名為 demo4_lib.go,并且放在與 demo4.go 相同的目錄下。如下:

// 需在此處添加代碼。[1]
 
import "fmt"
 
func hello(name string) {
 fmt.Printf("Hello, %s!\n", name)
}

那么問題來了:注釋 1 處應(yīng)該填入什么代碼?

典型回答

答案很簡單,填入代碼包聲明語句package main。為什么?我之前說過,在同一個目錄下的源碼文件都需要被聲明為屬于同一個代碼包。

如果該目錄下有一個命令源碼文件,那么為了讓同在一個目錄下的文件都通過編譯,其他源碼文件應(yīng)該也聲明屬于main包。

如此一來,我們就可以運行它們了。比如,我們可以在這些文件所在的目錄下運行如下命令并得到相應(yīng)的結(jié)果。

$ go run demo4.go demo4_lib.go
Hello, everyone!

或者,像下面這樣先構(gòu)建當(dāng)前的代碼包再運行。

$ go build puzzlers/article3/q1
$ ./q1   
Hello, everyone!

在這里,我把 demo4.go 和 demo4_lib.go 都放在了一個相對路徑為puzzlers/article3/q1的目錄中。

在默認(rèn)情況下,相應(yīng)的代碼包的導(dǎo)入路徑會與此一致。我們可以通過代碼包的導(dǎo)入路徑引用其中聲明的程序?qū)嶓w。但是,這里的情況是不同的。

注意,demo4.go 和 demo4_lib.go 都聲明自己屬于main包。我在前面講 Go 語言源碼的組織方式的時候提到過這種用法,即:源碼文件聲明的包名可以與其所在目錄的名稱不同,只要這些文件聲明的包名一致就可以。

順便說一下,我為本專欄創(chuàng)建了一個名為“Golang_Puzzlers”的項目。該項目的 src 子目錄下會存有我們涉及的所有代碼和相關(guān)文件。

也就是說,正確的用法是,你需要把該項目的打包文件下載到本地的任意目錄下,然后經(jīng)解壓縮后把“Golang_Puzzlers”目錄加入到環(huán)境變量GOPATH中。還記得嗎?這會使“Golang_Puzzlers”目錄成為工作區(qū)之一。

問題解析

這個問題考察的是代碼包聲明的基本規(guī)則。這里再總結(jié)一下。

第一條規(guī)則,同目錄下的源碼文件的代碼包聲明語句要一致。也就是說,它們要同屬于一個代碼包。這對于所有源碼文件都是適用的。

如果目錄中有命令源碼文件,那么其他種類的源碼文件也應(yīng)該聲明屬于main包。這也是我們能夠成功構(gòu)建和運行它們的前提。

第二條規(guī)則,源碼文件聲明的代碼包的名稱可以與其所在的目錄的名稱不同。在針對代碼包進行構(gòu)建時,生成的結(jié)果文件的主名稱與其父目錄的名稱一致。

對于命令源碼文件而言,構(gòu)建生成的可執(zhí)行文件的主名稱會與其父目錄的名稱相同,這在我前面的回答中也驗證過了。

好了,經(jīng)過我的反復(fù)強調(diào),相信你已經(jīng)記住這些規(guī)則了。下面的內(nèi)容也將會與它們相關(guān)。

在編寫真正的程序時,我們僅僅把代碼拆分到幾個源碼文件中是不夠的。我們往往會用模塊化編程的方式,根據(jù)代碼的功能和用途把它們放置到不同的代碼包中。不過,這又會牽扯進一些 Go 語言的代碼組織規(guī)則。我們一起來往下看。

知識精講

1. 怎樣把命令源碼文件中的代碼拆分到其他代碼包?

我們先不用關(guān)注拆分代碼的技巧。我在這里仍然依從前面的拆分方法。我把 demo4.go 另存為 demo5.go,并放到一個相對路徑為puzzlers/article3/q2的目錄中。

然后我再創(chuàng)建一個相對路徑為puzzlers/article3/q2/lib的目錄,再把 demo4_lib.go 復(fù)制一份并改名為 demo5_lib.go 放到該目錄中。

現(xiàn)在,為了讓它們通過編譯,我們應(yīng)該怎樣修改代碼?你可以先思考一下。我在這里給出一部分答案,我們一起來看看已經(jīng)過修改的 demo5_lib.go 文件。

package lib5
 
import "fmt"
 
func Hello(name string) {
 fmt.Printf("Hello, %s!\n", name)
}

可以看到,我在這里修改了兩個地方。第一個改動是,我把代碼包聲明語句由package main改為了package lib5。注意,我故意讓聲明的包名與其所在的目錄的名稱不同。第二個改動是,我把全小寫的函數(shù)名hello改為首字母大寫的Hello。

基于以上改動,我們再來看下面的幾個問題。

2. 代碼包的導(dǎo)入路徑總會與其所在目錄的相對路徑一致嗎?

庫源碼文件 demo5_lib.go 所在目錄的相對路徑是puzzlers/article3/q2/lib,而它卻聲明自己屬于lib5包。在這種情況下,該包的導(dǎo)入路徑是puzzlers/article3/q2/lib,還是puzzlers/article3/q2/lib5?

這個問題往往會讓 Go 語言的初學(xué)者們困惑,就算是用 Go 開發(fā)過程序的人也不一定清楚。我們一起來看看。

首先,我們在構(gòu)建或者安裝這個代碼包的時候,提供給go命令的路徑應(yīng)該是目錄的相對路徑,就像這樣:

go install puzzlers/article3/q2/lib

該命令會成功完成。之后,當(dāng)前工作區(qū)的 pkg 子目錄下會產(chǎn)生相應(yīng)的歸檔文件,具體的相對路徑是:

pkg/darwin_amd64/puzzlers/article3/q2/lib.a

其中的darwin_amd64就是我在講工作區(qū)時提到的平臺相關(guān)目錄。可以看到,這里與源碼文件所在目錄的相對路徑是對應(yīng)的。

為了進一步說明問題,我需要先對 demo5.go 做兩個改動。第一個改動是,在以import為前導(dǎo)的代碼包導(dǎo)入語句中加入puzzlers/article3/q2/lib,也就是試圖導(dǎo)入這個代碼包。

第二個改動是,把對hello函數(shù)的調(diào)用改為對lib.Hello函數(shù)的調(diào)用。其中的lib.叫做限定符,旨在指明右邊的程序?qū)嶓w所在的代碼包。不過這里與代碼包導(dǎo)入路徑的完整寫法不同,只包含了路徑中的最后一級lib,這與代碼包聲明語句中的規(guī)則一致。

現(xiàn)在,我們可以通過運行g(shù)o run demo5.go命令試一試。錯誤提示會類似于下面這種。

./demo5.go:5:2: imported and not used: "puzzlers/article3/q2/lib" as lib5
./demo5.go:16:2: undefined: lib

第一個錯誤提示的意思是,我們導(dǎo)入了puzzlers/article3/q2/lib包,但沒有實際使用其中的任何程序?qū)嶓w。這在 Go 語言中是不被允許的,在編譯時就會導(dǎo)致失敗。

注意,這里還有另外一個線索,那就是“as lib5”。這說明雖然導(dǎo)入了代碼包puzzlers/article3/q2/lib,但是使用其中的程序?qū)嶓w的時候應(yīng)該以lib5.為限定符。這也就是第二個錯誤提示的原因了。Go 命令找不到lib.這個限定符對應(yīng)的代碼包。

為什么會是這樣?根本原因就是,我們在源碼文件中聲明所屬的代碼包與其所在目錄的名稱不同。請記住,源碼文件所在的目錄相對于 src 目錄的相對路徑就是它的代碼包導(dǎo)入路徑,而實際使用其程序?qū)嶓w時給定的限定符要與它聲明所屬的代碼包名稱對應(yīng)。

有兩個方式可以使上述構(gòu)建成功完成。我在這里選擇把 demo5_lib.go 文件中的代碼包聲明語句改為package lib。理由是,為了不讓該代碼包的使用者產(chǎn)生困惑,我們總是應(yīng)該讓聲明的包名與其父目錄的名稱一致。

3. 什么樣的程序?qū)嶓w才可以被當(dāng)前包外的代碼引用?

你可能會有疑問,我為什么要把 demo5_lib.go 文件中的那個函數(shù)名稱hello的首字母大寫?實際上這涉及了 Go 語言中對于程序?qū)嶓w訪問權(quán)限的規(guī)則。

超級簡單,名稱的首字母為大寫的程序?qū)嶓w才可以被當(dāng)前包外的代碼引用,否則它就只能被當(dāng)前包內(nèi)的其他代碼引用。

通過名稱,Go 語言自然地把程序?qū)嶓w的訪問權(quán)限劃分為了包級私有的和公開的。對于包級私有的程序?qū)嶓w,即使你導(dǎo)入了它所在的代碼包也無法引用到它。

4. 對于程序?qū)嶓w,還有其他的訪問權(quán)限規(guī)則嗎?

答案是肯定的。在 Go 1.5 及后續(xù)版本中,我們可以通過創(chuàng)建internal代碼包讓一些程序?qū)嶓w僅僅能被當(dāng)前模塊中的其他代碼引用。這被稱為 Go 程序?qū)嶓w的第三種訪問權(quán)限:模塊級私有。

具體規(guī)則是,internal代碼包中聲明的公開程序?qū)嶓w僅能被該代碼包的直接父包及其子包中的代碼引用。當(dāng)然,引用前需要先導(dǎo)入這個internal包。對于其他代碼包,導(dǎo)入該internal包都是非法的,無法通過編譯。

“Golang_Puzzlers”項目的puzzlers/article3/q4包中有一個簡單的示例,可供你查看。你可以改動其中的代碼并體會internal包的作用。

總結(jié)

我們在本篇文章中詳細(xì)討論了把代碼從命令源碼文件中拆分出來的方法,這包括拆分到其他庫源碼文件,以及拆分到其他代碼包。

這里涉及了幾條重要的 Go 語言基本編碼規(guī)則,即:代碼包聲明規(guī)則、代碼包導(dǎo)入規(guī)則以及程序?qū)嶓w的訪問權(quán)限規(guī)則。在進行模塊化編程時,你必須記住這些規(guī)則,否則你的代碼很可能無法通過編譯。

思考題

  1. 如果你需要導(dǎo)入兩個代碼包,而這兩個代碼包的導(dǎo)入路徑的最后一級是相同的,比如:dep/lib/flag和flag,那么會產(chǎn)生沖突嗎?如果會產(chǎn)生沖突,那么怎樣解決這種沖突,有幾種方式?

到此這篇關(guān)于模塊一 GO語言基礎(chǔ)知識-庫源碼文件的文章就介紹到這了,更多相關(guān)GO語言庫源碼文件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:
  • GO語言(golang)基礎(chǔ)知識
  • Go語言基礎(chǔ)知識總結(jié)(語法、變量、數(shù)值類型、表達(dá)式、控制結(jié)構(gòu)等)
  • Go語言基礎(chǔ)知識點介紹

標(biāo)簽:西雙版納 海南 青海 安康 遼寧 物業(yè)服務(wù) 電子產(chǎn)品 儋州

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《模塊一 GO語言基礎(chǔ)知識-庫源碼文件》,本文關(guān)鍵詞  模塊,一,語言,基礎(chǔ)知識,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請?zhí)峁┫嚓P(guān)信息告之我們,我們將及時溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《模塊一 GO語言基礎(chǔ)知識-庫源碼文件》相關(guān)的同類信息!
  • 本頁收集關(guān)于模塊一 GO語言基礎(chǔ)知識-庫源碼文件的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章
    主站蜘蛛池模板: 垦利县| 海门市| 云南省| 扬州市| 游戏| 彩票| 临武县| 伊宁市| 武义县| 蓝田县| 广南县| 陵水| 张家界市| 兴文县| 永顺县| 满城县| 延川县| 河南省| 黎平县| 稷山县| 恭城| 瓮安县| 荆门市| 榕江县| 西平县| 武安市| 汕头市| 梅州市| 孝感市| 抚松县| 正安县| 馆陶县| 红原县| 阜新市| 东辽县| 牙克石市| 通河县| 明光市| 芦溪县| 河南省| 西盟|