C語言中文網 目錄

Go語言import導入包——在代碼中使用其他的代碼

要引用其他包的標識符,可以使用 import 關鍵字,導入的包名使用雙引號包圍,包名是從 GOPATH 開始計算的路徑,使用/進行路徑分隔。

默認導入的寫法

導入有兩種基本格式,即單行導入和多行導入,兩種導入方法的導入代碼效果是一致的。

1) 單行導入

單行導入格式如下:

import "包1"
import "包2"

2) 多行導入

當多行導入時,包名在 import 中的順序不影響導入效果,格式如下:

import(
    "包1"
    "包2"
    …
)

參考代碼 8-1 的例子來理解 import 的機制。
本套教程所有源碼下載地址:https://pan.baidu.com/s/1ORFVTOLEYYqDhRzeq0zIiQ    提取密碼:hfyf
代碼 8-1 的目錄層次如下:

.
└── src
    └── chapter08
        └── importadd
            ├── main.go
            └── mylib
                └── add.go


代碼8-1 加函數(具體文件:…/chapter08/importadd/mylib/add.go)
package mylib

func Add(a, b int) int {
    return a + b
}
第 3 行中的 Add() 函數以大寫 A 開頭,表示將 Add() 函數導出供包外使用。當首字母小寫時,為包內使用,包外無法引用到。

add.go 在 mylib 文件夾下,習慣上將文件夾的命名與包名一致,命名為 mylib 包。

代碼8-2 導入包(具體文件:…/chapter08/importadd/main.go)
package main

import (
    "chapter08/importadd/mylib"
    "fmt"
)

func main() {
    fmt.Println(mylib.Add(1, 2))
}
代碼說明如下:
  • 第 4 行,導入 chapter08/importadd/mylib 包。
  • 第 9 行,使用 mylib 作為包名,并引用 Add() 函數調用。

在命令行中運行下面代碼:

export GOPATH=/home/davy/golangbook/code
go install chapter08/importadd
$GOPATH/bin/importadd

命令說明如下:
  • 第 1 行,根據你的 GOPATH 不同,設置 GOPATH。
  • 第 2 行,使用 go install 指令編譯并安裝 chapter08/code8-1 到 GOPATH 的 bin 目錄下。
  • 第 3 行,執行 GOPATH 的 bin 目錄下的可執行文件 code8-1。

運行代碼,輸出結果如下:
3

導入包后自定義引用的包名

在默認導入包的基礎上,在導入包路徑前添加標識符即可形成自定義引用包,格式如下:

customName "path/to/package"

其中,path/to/package 為要導入的包路徑,customName 為自定義的包名。

在 code8-1 的基礎上,在 mylib 導入的包名前添加一個標識符,代碼如下:
package main

import (
    renameLib "chapter08/importadd/mylib"
    "fmt"
)

func main() {
    fmt.Println(renameLib.Add(1, 2))
}
代碼說明如下:
  • 第 4 行,將 chapter08/importadd/mylib 包導入,并且使用 renameLib 進行引用。
  • 第 9 行,使用 renameLib 調用 chapter08/importadd/mylib 包中的 Add() 函數。

匿名導入包——只導入包但不使用包內類型和數值

如果只希望導入包,而不使用任何包內的結構和類型,也不調用包內的任何函數時,可以使用匿名導入包,格式如下:
import (
    _ "path/to/package"
)
其中,path/to/package 表示要導入的包名,下畫線_表示匿名導入包。

匿名導入的包與其他方式導入包一樣會讓導入包編譯到可執行文件中,同時,導入包也會觸發 init() 函數調用。

包在程序啟動前的初始化入口:init

在某些需求的設計上需要在程序啟動時統一調用程序引用到的所有包的初始化函數,如果需要通過開發者手動調用這些初始化函數,那么這個過程可能會發生錯誤或者遺漏。我們希望在被引用的包內部,由包的編寫者獲得代碼啟動的通知,在程序啟動時做一些自己包內代碼的初始化工作。

例如,為了提高數學庫計算三角函數的執行效率,可以在程序啟動時,將三角函數的值提前在內存中建成索引表,外部程序通過查表的方式迅速獲得三角函數的值。但是三角函數索引表的初始化函數的調用不希望由每一個外部使用三角函數的開發者調用,如果在三角函數的包內有一個機制可以告訴三角函數包程序何時啟動,那么就可以解決初始化的問題。

Go 語言為以上問題提供了一個非常方便的特性:init() 函數。

init() 函數的特性如下:
  • 每個源碼可以使用 1 個 init() 函數。
  • init() 函數會在程序執行前(main() 函數執行前)被自動調用。
  • 調用順序為 main() 中引用的包,以深度優先順序初始化。

例如,假設有這樣的包引用關系:main→A→B→C,那么這些包的 init() 函數調用順序為:

C.init→B.init→A.init→main

說明:
  • 同一個包中的多個 init() 函數的調用順序不可預期。
  • init() 函數不能被其他函數調用。

理解包導入后的init()函數初始化順序

Go 語言包會從 main 包開始檢查其引用的所有包,每個包也可能包含其他的包。Go 編譯器由此構建出一個樹狀的包引用關系,再根據引用順序決定編譯順序,依次編譯這些包的代碼。

在運行時,被最后導入的包會最先初始化并調用 init() 函數。

通過下面的代碼理解包的初始化順序。

代碼8-3 包導入初始化順序入口(…/chapter08/pkginit/main.go)
package main

import "chapter08/code8-2/pkg1"

func main() {

    pkg1.ExecPkg1()
}
代碼說明如下:
  • 第 3 行,導入 pkg1 包。
  • 第 7 行,調用 pkg1 包的 ExecPkg1() 函數。

代碼8-4 包導入初始化順序pkg1(…/chapter08/pkginit/pkg1/pkg1.go)
package pkg1

import (
    "chapter08/code8-2/pkg2"
    "fmt"
)

func ExecPkg1() {

    fmt.Println("ExecPkg1")

    pkg2.ExecPkg2()
}

func init() {
    fmt.Println("pkg1 init")
}
代碼說明如下:
  • 第 4 行,導入 pkg2 包。
  • 第 8 行,聲明 ExecPkg1() 函數。
  • 第 12 行,調用 pkg2 包的 ExecPkg2() 函數。
  • 第 15 行,在 pkg1 包初始化時,打印 pkg1 init。

代碼8-5 包導入初始化順序pkg2(…/chapter08/pkginit/pkg2/pkg2.go)
package pkg2

import "fmt"

func ExecPkg2() {
    fmt.Println("ExecPkg2")
}

func init() {
    fmt.Println("pkg2 init")
}
代碼說明如下:
  • 第 5 行,聲明 ExecPkg2() 函數。
  • 第 10 行,在 pkg2 包初始化時,打印 pkg2 init。

執行代碼,輸出如下:
pkg2 init
pkg1 init
ExecPkg1
ExecPkg2

精美而實用的網站,提供C語言C++STLLinuxShellJavaGo語言等教程,以及socketGCCviSwing設計模式JSP等專題。

Copyright ?2011-2018 biancheng.net, 陜ICP備15000209號

底部Logo