日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

go——工程结构

發布時間:2024/4/17 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 go——工程结构 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Go是一門推崇軟件工程理念的編程語言,它為開發周期的每個環節都提供了完備的工具和支持。

Go語言高度強調代碼和項目的規范和統一,這幾種體現在工程結構或者說代碼體制的細節之處。

1.工作區

一般情況下,Go源碼文件必須放在工作區中。但是對于命令源碼文件來說,這不是必須的。
工作區其實就是一個對應于特定工程的目錄,它應該包含3個子目錄:src目錄、pkg目錄和bin目錄。

(1)src目錄

用于以代碼包的形式組織并保存Go源碼文件,這里的代碼包與src下的子目錄一一對應。
例如,若一個源碼文件被聲明屬于代碼包log,那么它就應該保存在src/log目錄下。
當然,你也可以直接把Go源碼文件直接放在src目錄下,但這樣的Go源碼文件就只能被聲明屬于main代碼包。
除非用于臨時測試或演示,一般還是建議把Go源碼文件放入特定的代碼包中。

(2)pkg目錄

用于存放通過go install命令安裝后的代碼包的歸檔文件。
前提是代碼包中必須包含Go庫源碼文件。歸檔文件是指那些名稱以“.a”結尾的文件。
該目錄與GOROOT目錄下的pkg目錄功能類似。
區別在于,工作區中的pkg目錄專門用來存放用戶代碼的歸檔文件。
編譯和安裝用戶代碼的過程一般會以代碼包為單位進行。
比如log包被編譯安裝后,將生成一個名為log.a的歸檔文件,并存放在當前工作區的pkg目錄下的平臺相關目錄中。

(3)bin目錄

與pkg目錄類似,在通過go install命令完成安裝后,保存由Go命令源碼文件生成的可執行文件。
(其實上面文字的意思就是什么類型的文件放在什么目錄下面,盡量規劃好工作區)

命令源碼文件:就是聲明屬于main代碼包并包含無參聲明和結果聲明的main函數的源碼文件。
這類源碼文件就是程序的入口,它們可以獨立運行(使用go run命令),
也可以通過go build或go install命令得到相應的可執行文件。

庫源碼文件:是指存在于某個代碼包中普通源碼文件。

?

2.源碼文件

(1)命令源碼文件

如果一個源碼文件被聲明屬于main代碼包,且該文件代碼中包含無參數聲明和結果聲明的main函數,則它就是命令源碼文件。
命令源碼文件可以直接通過go run命令直接啟動運行。

同一個代碼中的所有的源碼文件,其所屬代碼包的名稱必須一致。
如果命令源碼文件和庫源碼文件處于同一個代碼包中,那么在該包中就無法正確執行go build和go install命令。
換句話說,這些源碼文件將無法通過常規方法編譯和安裝。
因此,命令源碼文件通常會單獨放在一個代碼包中,因為通常一個程序模塊或軟件的啟動入口只有一個。

同一個代碼包中可以有多個命令源碼文件,可通過go run命令分別運行,但這會使go build和go install命令無法編譯和安裝該代碼包。

當代碼包中有且只有一個命令源碼文件時,在文件所在目錄中執行go build命令,
則可在該目錄下生成一個與目錄同名的可執行文件;

? 若使用go install命令,則可在當前工作區的bin目錄下生成相應的可執行文件。

需要注意的是,只有當前環境變量GOPATH中只包含一個工作區的目錄路徑時,
go install命令才會把命令源碼文件安裝到當前工作區的bin目錄下;

?

(2)庫源碼文件

通常,庫源碼文件聲明的包名會與它直接所屬的代碼包一致,且庫源碼文件中不包含無參數聲明和無結果聲明的main函數。

通過執行go install命令,成功安裝了該包并生成了若干歸檔文件。

由于我們指定了工作區GOPATH的路徑是/root/example.v2,則會在這個目錄下生成bin和pkg文件。
run install之前:

? run install之后:

?

?

(3)測試源碼文件

測試源碼文件是一種特殊的庫文件,可以通過執行go test命令運行當前代碼包下的所有測試源碼文件。
成為測試源碼文件的充分條件有兩個:
  A.文件名需要以"_test.go"結尾
  B.文件中需要至少包含一個名稱以Test開頭或Benchmark開頭,且擁有一個類型為*testing.T或*testing.B的參數的函數。
  *testing.T或*testing.B是兩個結構體類型。而*testing.T或*testing.B則分別為前兩者的指針類型。它們分別是功能測試和基準測試所需。

? 當在一個代碼包中之心go test命令時,該代碼包中的所有測試源碼文件會被找到并運行。

?

3.代碼包

在Go中,代碼包是代碼編譯和安裝的基本單元,也是非常直觀的代碼組織形式。

(1)包聲明

在Go語言中,代碼包中的源碼文件可以任意命令。
但是,這些任意名稱的源碼文件都必須以包聲明語句作為文件代碼中的第一行。
例如,example.v2/src/gopcp.v2/helper/log/base包中的所有源碼文件都先聲明自己屬于某一個代碼包:

? 分別打印第一行:

? 其中,package是Go中用于包聲明語句的關鍵字。
Go規定包聲明中的包名是代碼路徑的最后一個元素。

? 所以包名是base。
但是,不論命令源文件存放在哪個代碼包中,它都必須聲明屬于main包。


(2)包導入


代碼包gopcp.v2/helper/log中的logger.go需要依賴base子包和logrus子包,

因此需要在源碼文件中使用代碼包導入語句,如:

import "gopcp.v2/helper/log/base" import "gopcp.v2/helper/log/logrus"

全路徑是:/root/example.v2/src/gopcp.v2/helper/log,但是所有的源代碼都在src下面,所以這里使用相對路徑。

當導入多個代碼包時,你需要用圓括號,每個代碼包名占一行。

import ( "gopcp.v2/helper/log/base" "gopcp.v2/helper/log/logrus" )

同一個源碼文件中導入多個代碼包的最后一個元素不能重復,否則一旦使用其中的程序實體,就會引起編譯錯誤。
但是,如果你只導入不適用,同樣會引起編譯錯誤,一個解決辦法就是為其中一個起別名。

import ( "gopcp.v2/helper/log/logrus" mylogrus "gopcp.v2/helper/log/logrus" )

如果我們想不加前綴而直接使用某個依賴包中的程序實體,就可以用"."來代替別名。

import ( . "gopcp.v2/helper/log/logrus" )

所以我們就可以這樣引用:

var logger = NewLogger("gopcp") //NewLogger是logrus中的一個函數。

我們可以看到,因為"."的緣故,可以直接引用包中的函數,而不需要指定路徑。

在Go中,變量、常量、函數和類型聲明可統稱為程序實體,而它們的名稱統稱為標識符。
標識符可以是Unicode字符集中任意能表示自然語言文字的字符、數字以及下劃線(_)。標識符不能以數字或下劃線開頭。

實際上,標識符的首字符的大小寫控制著對應程序實體的訪問權限。
如果標識符的首字符是大寫形式,那么它所對應的程序實體就可以被本代碼之外的代碼訪問到,也稱之為可導出或公開的;
否則,對應的程序實體就只能被本包內的代碼訪問,也成為不可導出的或包私有的。
要想成為可導出的程序實體,還需要額外滿足以下兩個條件。
程序實體必須是非局部的。局部的程序實體是指:它被定義在了函數或結構體的內部。
代碼包所屬目錄必須包含在GOPATH中定義的工作區目錄中。

代碼包導入還有另一種情況:如果只想初始化某個代碼包,
而不需要在當前源碼文件中使用那個代碼包中的任何程序實體,就可以用“_”來代替別名。

import ( _ "gopcp.v2/helper/log/logrus" )

這種情況下,我們只是觸發了這個代碼包的初始化操作,符號"_"就像一個垃圾桶。


(3)包初始化


在Go中,可以有專門的函數負責代碼包初始化,成為代碼包初始化函數。
這個函數無任何參數聲明和結果聲明,且名稱必須為init。

func init() { fmt.PrintLn("Initialize...") }

Go會在程序真正執行前對整個程序的依賴進行分析,并初始化相關的代碼包。
也就是說,所有的代碼包初始化函數都會在main函數(命令源碼文件的入口函數)執行前執行完畢,而且只會執行一次。
另外,對于每一個代碼包來說,其中的所有全局變量的初始化,都會在代碼包的初始化函數執行前完成。
這避免了在代碼包初始化函數對某個變量進行賦值之后,又被該變量聲明中賦予的值覆蓋掉的問題
下面是一個簡單示例:

//如果一個源碼文件被聲明屬于main代碼包,且該文件代碼包含無參數聲明和結果聲明的main函數,則它就是命令源碼文件。 package main //命令源碼文件必須在這里聲明自己屬于main包 import ( //導入標準庫代碼包fmt和runtime "fmt" "runtime" ) func init() { //代碼初始化函數 fmt.Printf("Map: %v\n", m) //這里可以直接獲取到變量m,可以看出變量的初始化在代碼包初始化之前完成 //通過runtime獲取當前操作系統和計算架構 //通過fmt的Sprintf進行格式化然后賦值給info info = fmt.Sprintf("OS:%s,Arch:%s", runtime.GOOS, runtime.GOARCH) }//非局部變量,map類型,且已初始化,因為已經賦值 var m = map[int]string{1: "A", 2: "B", 3: "C"} //非局部變量,string類型,未初始化,因為還未賦值 var info stringfunc main() { //命令源碼文件必須有入口函數,也可以叫做主函數 fmt.Println(info) //代碼包的初始化會在main函數執行前執行完畢 }//同一個代碼包中可以存在多個代碼初始化函數,甚至代碼包內的每一個源碼文件都可以定義多個代碼初始化函數。 //Go不會保證同一個代碼包中多個代碼包初始化函數的執行順序。 //被導入的代碼吧的初始化函數總是會先執行,例如上面fmt和runtime中如果有init函數,那么就會先執行。

  

?

轉載于:https://www.cnblogs.com/yangmingxianshen/p/10089615.html

總結

以上是生活随笔為你收集整理的go——工程结构的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。