欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Go?的入口函數(shù)和包初始化的使用

 更新時(shí)間:2022年05月10日 08:31:41   作者:小菠蘿測(cè)試筆記  
本文主要介紹了Go?的入口函數(shù)和包初始化的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

包 package

  • Go 包是 Go 語(yǔ)言的基本組成單元,一個(gè) Go 程序就是一組包的集合,所有 Go 代碼都位于包中
  • Go 源碼可以導(dǎo)入其他 Go 包,并使用其中的導(dǎo)出語(yǔ)法元素,包括類型、變量、函數(shù)、方法等,而且 main 函數(shù)是整個(gè) Go 應(yīng)用的入口函數(shù)
  • Go 語(yǔ)言提供了很多內(nèi)置包,如 fmt、os、io 等
  • 任何源代碼文件必須屬于某個(gè)包,同時(shí)源碼文件的第一行有效代碼必須是 package 包名語(yǔ)句,通過(guò)該語(yǔ)句聲明源碼文件所在的包

main.main 函數(shù):Go 應(yīng)用的入口函數(shù)

  • Go 語(yǔ)言中有一個(gè)特殊的函數(shù):main 包中的 main 函數(shù),也就是 main.main,它是所有 Go 可執(zhí)行程序的用戶層執(zhí)行邏輯的入口函數(shù)
  • Go 程序在用戶層面的執(zhí)行邏輯,會(huì)在這個(gè)函數(shù)內(nèi)按照它的調(diào)用順序展開(kāi)

package main

  • 整個(gè) Go 可執(zhí)行程序中僅允許存在一個(gè)名為 main 的包
  • package main想要引用別的包的代碼,必須同樣以包的方式進(jìn)行引用
package main

func main() {    
    // 用戶層執(zhí)行邏輯
    ... ...
}

Go 語(yǔ)言要求:可執(zhí)行程序的 main 包必須定義 main 函數(shù),否則 Go 編譯器會(huì)報(bào)錯(cuò)

注意

main 包是不可以像標(biāo)準(zhǔn)庫(kù) fmt 包那樣被導(dǎo)入(Import)的

其他包也可以擁有 main 函數(shù)或方法

按照 Go 的可見(jiàn)性規(guī)則(小寫字母卡頭的標(biāo)識(shí)符為非導(dǎo)出標(biāo)識(shí)符),非 main包中自定義的 main 函數(shù)僅限于包內(nèi)使用

package pkg1

import "fmt"

func Main () {
    main()
}

func main(){
    fmt.Println("main func for pkg1")
}

重點(diǎn)

  • 一個(gè)文件夾下的所有源碼文件只能屬于同一個(gè)包,不要求同名,但還是建議包名和所在目錄同名,這樣結(jié)構(gòu)更清晰,包名中不能包含特殊符號(hào)
  • 給結(jié)構(gòu)定義的方法必須放在同一個(gè)包內(nèi),可以是不同文件
  • 包名為 main 的包為應(yīng)用程序的入口包,編譯不包含 main 包的源碼文件時(shí)不會(huì)得到可執(zhí)行文件。
  • 一個(gè)文件夾下的所有源碼文件只能屬于同一個(gè)包,屬于同一個(gè)包的源碼文件不能放在多個(gè)文件夾下

引子

不過(guò)對(duì)于 main 包的main 函數(shù)來(lái)說(shuō),還需要明確一點(diǎn),就是它雖然是用戶層邏輯的入口函數(shù),但它卻不一定是用戶層第一個(gè)被執(zhí)行的函數(shù)。這是為什么呢?這跟 Go 語(yǔ)言的另一個(gè)函數(shù) init 有關(guān)

init 函數(shù):Go 包的初始化函數(shù)

和 main.main 函數(shù)一樣,init 函數(shù)也是一個(gè)無(wú)參數(shù)無(wú)返回值的函數(shù)

func init() {
	// 包初始化邏輯
	... ...
}
  • Go 程序會(huì)在這個(gè)包初始化的時(shí)候,自動(dòng)調(diào)用它的 init 函數(shù),所以 init 函數(shù)的執(zhí)行會(huì)發(fā)生在 main 函數(shù)之前
  • 在 Go 程序中不能手工顯式地調(diào)用 init,否則會(huì)收到編譯錯(cuò)誤

和 main 函數(shù)不一樣

  • init 函數(shù)在一個(gè)包中可以有多個(gè),每個(gè) Go 源文件都可以定義多個(gè) init 函數(shù)

init 函數(shù)的執(zhí)行順序

  • 在初始化 Go 包時(shí),Go 會(huì)按照一定的順序,逐一、順序地調(diào)用這個(gè)包的 init 函數(shù)
  • 一般來(lái)說(shuō),先傳遞給 Go 編譯器的源文件中的 init 函數(shù),會(huì)先被執(zhí)行;而同一個(gè)源文件中的多個(gè) init 函數(shù),會(huì)按聲明順序依次執(zhí)行

Go 包的初始化次序

  • 從程序邏輯結(jié)構(gòu)角度來(lái)看,Go 包是程序邏輯封裝的基本單元
  • 每個(gè)包都可以理解為是一個(gè)“自治”的、封裝良好的、對(duì)外部暴露有限接口的基本單元
  • 一個(gè) Go 程序就是由一組包組成的,程序的初始化就是這些包的初始化
  • 每個(gè) Go 包還會(huì)有自己的依賴包、常量、變量、init 函數(shù)(其中 main 包有 main 函數(shù))等

三步走

  • 依賴包按“深度優(yōu)先”的次序進(jìn)行初始化
  • 每個(gè)包內(nèi)按以“常量 -> 變量 -> init 函數(shù)”的順序進(jìn)行初始化
  • 包內(nèi)的多個(gè) init 函數(shù)按出現(xiàn)次序進(jìn)行自動(dòng)調(diào)用

init 函數(shù)的特點(diǎn)

  • 如上圖所示,執(zhí)行順位排在包內(nèi)其他語(yǔ)法元素(常量、變量)的后面
  • 每個(gè) init 函數(shù)在整個(gè) Go 程序生命周期內(nèi)僅會(huì)被執(zhí)行一次
  • init 函數(shù)是順序執(zhí)行的,只有當(dāng)一個(gè) init 函數(shù)執(zhí)行完畢后,才會(huì)去執(zhí)行下一個(gè) init 函數(shù)

init 函數(shù)的用途

重置包級(jí)變量值

init 函數(shù)就好比 Go 包真正投入使用之前唯一的“質(zhì)檢員”,負(fù)責(zé)對(duì)包內(nèi)部以及暴露到外部的包級(jí)數(shù)據(jù)(主要是包級(jí)變量)的初始狀態(tài)進(jìn)行檢查

實(shí)現(xiàn)對(duì)包級(jí)變量的復(fù)雜初始化

有些包級(jí)變量需要一個(gè)比較復(fù)雜的初始化過(guò)程,有些時(shí)候,使用它的類型零值或通過(guò)簡(jiǎn)單初始化表達(dá)式不能滿足業(yè)務(wù)邏輯要求,而 init 函數(shù)則非常適合完成此項(xiàng)工作,標(biāo)準(zhǔn)庫(kù) http 包中就有這樣一個(gè)典型示例

package main

import (
	"os"
	"strings"
)

var (
	http2VerboseLogs    bool // 初始化默認(rèn)值 false
	http2logFrameWrites bool
	http2logFrameReads  bool
	http2inTests        bool
)

func init() {
	e := os.Getenv("GODEBUG")
	if strings.Contains(e, "http2debug=1") {
		http2VerboseLogs = true // 在 init 中對(duì) http2VerboseLogs 的值進(jìn)行重置
	}
	if strings.Contains(e, "http2debug=2") {
		http2logFrameWrites = true
		http2logFrameReads = true
		http2inTests = true
	}
}

http 包在init 函數(shù)中,就根據(jù)環(huán)境變量 GODEBUG 的值,對(duì)這些包級(jí)開(kāi)關(guān)變量進(jìn)行了復(fù)雜的初始化,從而保證了這些開(kāi)關(guān)變量在 http 包完成初始化后,可以處于合理狀態(tài)

在 init 函數(shù)中實(shí)現(xiàn)“注冊(cè)模式”

來(lái)看一段使用 lib/pq 包訪問(wèn) PostgreSQL 數(shù)據(jù)庫(kù)的代碼 ??

package main

import (
	"database/sql"
	"log"

	_ "github.com/lib/pq"
)

func main() {
	db, err := sql.Open("postgres", "user=pqgotest dbname=pqgotest sslmode=ver)
	if err != nil {
		log.Fatal(err)
	}
	age := 21
	rows, err := db.Query("SELECT name FROM users WHERE age = $1", age)
}
復(fù)制代碼

這里是以空導(dǎo)入_的方式導(dǎo)入 lib/pq 包的,main 函數(shù)中沒(méi)有使用 pq 包的任何變量、函數(shù)或方法,這樣就實(shí)現(xiàn)了對(duì) PostgreSQL數(shù)據(jù)庫(kù)的訪問(wèn)

實(shí)際原因

在 pq 包的 conn.go 源碼文件中的 init 函數(shù)

func init() {
	sql.Register("postgres", &Driver{})
}
  • 利用了空導(dǎo)入的特性,將 lib/pq 包作為 main 包的依賴包,在包初始化時(shí),會(huì)先執(zhí)行 lib/pq 包里面的 init 函數(shù)
  • pq 包的 init 函數(shù)將自己實(shí)現(xiàn)的 sql 驅(qū)動(dòng)注冊(cè)到了 sql 包中
  • 這樣在實(shí)際應(yīng)用代碼中,Open 數(shù)據(jù)庫(kù)時(shí),傳入驅(qū)動(dòng)名字(這里是 postgres),就能得到數(shù)據(jù)庫(kù)實(shí)例,然后對(duì)數(shù)據(jù)庫(kù)進(jìn)行操作,實(shí)際上是因?yàn)檎{(diào)用了 pq 包中相應(yīng)的驅(qū)動(dòng)實(shí)現(xiàn)的

好處:這種通過(guò)在 init 函數(shù)中注冊(cè)自己的實(shí)現(xiàn)的模式,就有效降低了 Go 包對(duì)外的直接暴露,尤其是包級(jí)變量的暴露,從而避免了外部通過(guò)包級(jí)變量對(duì)包狀態(tài)的改動(dòng)

工廠設(shè)計(jì)模式

從標(biāo)準(zhǔn)庫(kù) database/sql 包的角度來(lái)看,這種“注冊(cè)模式”實(shí)質(zhì)是一種工廠設(shè)計(jì)模式的實(shí)現(xiàn),sql.Open 函數(shù)就是這個(gè)模式中的工廠方法,它根據(jù)外部傳入的驅(qū)動(dòng)名稱“生產(chǎn)”出不同類別的數(shù)據(jù)庫(kù)實(shí)例句柄

通過(guò)注冊(cè)模式實(shí)現(xiàn)獲取各種格式圖片的寬、高

Go 源碼

package main

import (
	"fmt"
	"image"
	_ "image/gif"
	_ "image/jpeg"
	_ "image/png"
	"os"
)

func main() {
	// 支持 png、jpeg、gif
	width, height, err := imageSize(os.Args[1])
	if err != nil {
		fmt.Println("get image size error:", err)
		return
	}
	fmt.Printf("image size: [%d,%d]\n", width, height)
}

func imageSize(imageFile string) (int, int, error) {
    // 打開(kāi)圖片文件
	f, _ := os.Open(imageFile)
	defer f.Close()
	
    // 對(duì)文件進(jìn)行解碼,得到圖片實(shí)例
	img, _, err := image.Decode(f)
	if err != nil {
		return 0, 0, err
	}
	
    // 返回圖片區(qū)域
	b := img.Bounds()
	return b.Max.X, b.Max.Y, nil
}
  • 上面的源碼支持 png、jpeg、gif 三種格式的圖片
  • 但并不需要手動(dòng)支持圖片格式
  • 是因?yàn)?image/png、image/jpeg 和 image/gif 包都在各自的 init 函數(shù)中,將自己“注冊(cè)”到 image 的支持格式列表中了
// $GOROOT/src/image/png/reader.go
func init() {
	image.RegisterFormat("png", pngHeader, Decode, DecodeConfig)
}

// $GOROOT/src/image/jpeg/reader.go
func init() {
	image.RegisterFormat("jpeg", "\xff\xd8", Decode, DecodeConfig)
}

// $GOROOT/src/image/gif/reader.go
func init() {
	image.RegisterFormat("gif", "GIF8?a", Decode, DecodeConfig)
}

到此這篇關(guān)于Go 的入口函數(shù)和包初始化的使用的文章就介紹到這了,更多相關(guān)Go 入口函數(shù)和包初始化內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go 庫(kù)性能分析工具pprof

    Go 庫(kù)性能分析工具pprof

    這篇文章主要為大家介紹了Go 庫(kù)性能分析工具pprof,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • golang中map增刪改查的示例代碼

    golang中map增刪改查的示例代碼

    在Go語(yǔ)言中,map是一種內(nèi)置的數(shù)據(jù)結(jié)構(gòu),用于存儲(chǔ)鍵值對(duì),本文主要介紹了golang中map增刪改查的示例代碼,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-11-11
  • 分析Go語(yǔ)言中CSP并發(fā)模型與Goroutine的基本使用

    分析Go語(yǔ)言中CSP并發(fā)模型與Goroutine的基本使用

    我們都知道并發(fā)是提升資源利用率最基礎(chǔ)的手段,尤其是當(dāng)今大數(shù)據(jù)時(shí)代,流量對(duì)于一家互聯(lián)網(wǎng)企業(yè)的重要性不言而喻。串流顯然是不行的,尤其是對(duì)于web后端這種流量的直接載體。并發(fā)是一定的,問(wèn)題在于怎么執(zhí)行并發(fā)。常見(jiàn)的并發(fā)方式有三種,分別是多進(jìn)程、多線程和協(xié)程
    2021-06-06
  • Go語(yǔ)言題解LeetCode35搜索插入位置示例詳解

    Go語(yǔ)言題解LeetCode35搜索插入位置示例詳解

    這篇文章主要為大家介紹了Go語(yǔ)言題解LeetCode35搜索插入位置示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • Golang操作excel的方法

    Golang操作excel的方法

    這篇文章主要介紹了Golang操作excel的方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-10-10
  • golang之?dāng)?shù)據(jù)校驗(yàn)的實(shí)現(xiàn)代碼示例

    golang之?dāng)?shù)據(jù)校驗(yàn)的實(shí)現(xiàn)代碼示例

    這篇文章主要介紹了golang之?dāng)?shù)據(jù)校檢的實(shí)現(xiàn)代碼示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • Go語(yǔ)言開(kāi)發(fā)瀏覽器視頻流rtsp轉(zhuǎn)webrtc播放

    Go語(yǔ)言開(kāi)發(fā)瀏覽器視頻流rtsp轉(zhuǎn)webrtc播放

    這篇文章主要為大家介紹了Go語(yǔ)言開(kāi)發(fā)瀏覽器視頻流rtsp轉(zhuǎn)webrtc播放的過(guò)程示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-04-04
  • Go語(yǔ)言中實(shí)現(xiàn)enum枚舉的方法詳解

    Go語(yǔ)言中實(shí)現(xiàn)enum枚舉的方法詳解

    枚舉,即?enum,可用于表示一組范圍固定的值,它能助我們寫出清晰、安全的代碼,那么你是否了解過(guò)?Go?中的枚舉呢?下面就跟隨小編一起來(lái)學(xué)習(xí)一下Go語(yǔ)言中實(shí)現(xiàn)enum枚舉的常用方法吧
    2024-02-02
  • golang中為什么Response.Body需要被關(guān)閉詳解

    golang中為什么Response.Body需要被關(guān)閉詳解

    這篇文章主要給大家介紹了關(guān)于golang中為什么Response.Body需要被關(guān)閉的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-08-08
  • Go?select使用與底層原理講解

    Go?select使用與底層原理講解

    這篇文章主要介紹了Go?select使用與底層原理講解,select是Go提供的IO多路復(fù)用機(jī)制,可以用多個(gè)cas同時(shí)監(jiān)聽(tīng)多個(gè)channl的讀寫狀態(tài),相關(guān)內(nèi)容需要的朋友可以參考一下
    2022-07-07

最新評(píng)論