第8章 包(package)
目录
- 第8章 包(package)
- 8.1 工作目录
- 8.1.1 命令行查看GOPATH信息
- 8.1.2 使用GOPATH的工程结构
- 8.1.3 设置和使用GOPATH
- 8.2 创建包package -- 编写自己的代码扩展
- 8.3 导出标识符 -- 让外部访问包的类型和值
- 8.4 导入包(import) -- 在代码中使用其他的代码
- 8.4.1默认导入写法
- 8.4.2 自定义命名导入包名
- 8.4.3 匿名导入包 -- 只导入包但不适用包内类型和数值
- 8.4.4 包在程序启动前的初始化入口:init
- 8.4.5 理解包导入后的init()函数初始化顺序
- 8.5 示例:工厂模式自动注册--管理过个包的结构体
8.1 工作目录
GOPATH是go语言使用的一个环境 变量,使用绝对路径
8.1.1 命令行查看GOPATH信息
go env
显示go开发环境配置信息:
$ go env
// 表示目标处理器架构
GOARCH="amd64"
//表示编译器和链接器的安装位置
GOBIN=""
GOCACHE="/Users/jihan/Library/Caches/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
//目标操作系统
GOOS="darwin"
//当前工作目录
GOPATH="/Users/jihan/go"
GOPROXY=""
GORACE=""
//GO开发包安装目录
GOROOT="/usr/local/go"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/vm/zby04lq56tg1y08qs5c6kkq80000gn/T/go-build459742728=/tmp/go-build -gno-record-gcc-switches -fno-common"
GOPATH在不同平台上的安装路径
平台 | GOPATH默认值 | 举例 |
---|---|---|
Window平台 | %USERPROFILE%/go | C:\Users\用户名\go |
Uninx平台 | $HOME/go | /home/用户名/go |
8.1.2 使用GOPATH的工程结构
GOPATH工作目录下,代码保存在$GOPATH/src目录下
通过go build\go install\go get等命令,将产生二进制可执行文件放在\(GOPATG/bin目录**下,生成中间缓存文件保存放在**\)GOPATG/pkg目录下
若需要将整个源码添加到版本控制工具中,只需将$GOPATH/src目录源码添加即可
8.1.3 设置和使用GOPATH
- 设置当前工作目录为GOPATH
- 建立GOPATH中源码目录
- 添加main.go源码文件
- 编译源码并运行
以下示例为linux平台操作
设置当前工作目录为GOPATH
export GOPATH=path
例如:
GOPATH="/Users/jihan/go"
export GOPATH=/Users/jihan/go
建立GOPATH中源码目录
mkdir -p src/hello
添加main.go源码文件
创建$GOPATH/src/main.go
package main
import "fmt"
func main() {
fmt.Println("hello")
}
编译源码并运行
go install hello
编译完可执行文件会保存在$GOPATH/bin目录下
./hello //进行执行
8.2 创建包package -- 编写自己的代码扩展
包要求在目录下的所有文件的第一行添加
package 包名
特性:
- 一个目录下的同级文件归属一个包
- 包名可以与目录不同名
- 包名为main的包为应用程序入口包,编译源码没有main包时,将无法编译输出可执行文件
8.3 导出标识符 -- 让外部访问包的类型和值
如果一个包引用另一个包的标识符(类型、变量、 常量时)必须首先将被引用的标识符导出
package mypkg
var myVar = 100
const myConst = "go"
type myStruct struct {}
将myStruct和myConst首字母大写,导出这些标识符
package mypkg
var MyVar = 100
const MyConst = "go"
type MyStruct struct {}
导出结构体及接口成员
结构体和接口成员同样字段或方法首字母大写,外部可以访问
type MyStruct struct {
//包外可以访问的字段
ExportField int
}
8.4 导入包(import) -- 在代码中使用其他的代码
使用import关键字,导入包包名使用双引号包围
8.4.1默认导入写法
- 单行导入
import "包1" import "包2"
- 多行导入
import ( "包1" "包2" )
导入包例子
importadd/mylib/add.go
package mylib
func Add(a, b int) int {
return a + b
}
eight/8.4/main.go
package main
import (
// 文件目录相对GOPATH的相对路径
"../../eight/8.4/mylib"
"fmt"
)
func main() {
fmt.Println(mylib.Add(1, 2))
}
8.4.2 自定义命名导入包名
格式
customName "path\to\package"
- path/to/package 导入包路径
- customName 自定义包名
package main
import (
renameMylib "../../eight/8.4/mylib"
"fmt"
)
func main() {
fmt.Println(renameMylib.Add(1, 2))
}
8.4.3 匿名导入包 -- 只导入包但不适用包内类型和数值
package main
import (
_ "../../eight/8.4/mylib"
"fmt"
)
func main() {
// fmt.Println(renameMylib.Add(1, 2))
}
8.4.4 包在程序启动前的初始化入口:init
特性:init()函数
- 每个源码可以食欲哦那个1个init()函数
- init()会在程序执行前(main()函数执行前)被自动调用
- 调用顺序为main()中引用的包,以深度优先顺序初始化
例如:包引用关系 main -> A->B->C 调用顺序为:c.init->B.init->A.init->main
- 同一个包的多个init()函数调用顺序不可以预期
- init()不能憋其他函数调用
8.4.5 理解包导入后的init()函数初始化顺序
go语言包会从main包开始检查其所有引用所有包,每个包也可能包含其他的包
go编译器由此构建一个树状的包引用关系,在根据引用顺序决定编译顺序,依次编译这些包的代码
在运行时,被最后导入的包会最先初始化并调用init()函数
例子:
文件目录:
.../eight/8.4.5
.../eight/8.4.5/pkginit
.../eight/8.4.5/pkginit/pkg1
.../eight/8.4.5/pkginit/pkg1/pkg1.go
.../eight/8.4.5/pkginit/pkg2
.../eight/8.4.5/pkginit/pkg2/pkg2.go
.../eight/8.4.5/pkginit/main.go
.../eight/8.4.5/pkginit/main.go
package main
import (
"../../../eight/8.4.5/pkginit/pkg1"
)
func main() {
pkg1.ExecPkg1()
}
.../eight/8.4.5/pkginit/pkg1/pkg1.go
package pkg1
import(
"../../../../eight/8.4.5/pkginit/pkg2"
"fmt"
)
func ExecPkg1() {
fmt.Println("ExecPkg1")
pkg2.ExecPkg2()
}
func init() {
fmt.Println("pkg1 init")
}
.../eight/8.4.5/pkginit/pkg2/pkg2.go
package pkg2
import(
"fmt"
)
func ExecPkg2() {
fmt.Println("ExecPkg2")
}
func init() {
fmt.Println("pkg2 init")
}
运行结果:
pkg2 init
pkg1 init
ExecPkg1
ExecPkg2
8.5 示例:工厂模式自动注册--管理过个包的结构体
利用包init()函数特性,将cls1和cls2两个包注册到工厂,使用字符串创建这两个注册好的结构实例
$HOME:src目录路径
目录结构:
$HOME/eight/8.5
$HOME/eight/8.5/clsfactory
$HOME/eight/8.5/clsfactory/base
$HOME/eight/8.5/clsfactory/base/factory.go
$HOME/eight/8.5/clsfactory/cls1
$HOME/eight/8.5/clsfactory/cls1/reg.go
$HOME/eight/8.5/clsfactory/cls2
$HOME/eight/8.5/clsfactory/cls2/reg.go
$HOME/eight/8.5/clsfactory/main.go
$HOME/eight/8.5/clsfactory/base/factory.go
package base
// 类接口
type Class interface {
Do()
}
// 声明保存工厂信息变量
var (
factoryByName = make(map[string]func() Class)
)
// 注册一个类生成工厂
func Register(name string, factory func() Class) {
factoryByName[name] = factory
}
// 根据名称创建对应的类
func Create(name string) Class {
if f, ok := factoryByName[name]; ok {
return f()
} else {
panic("name not found")
}
}
$HOME/eight/8.5/clsfactory/cls1/reg.go
package cls1
import (
"../../../../eight/8.5/clsfactory/base"
"fmt"
)
// 定义类1
type Class1 struct {
}
// 实现Class接口
func (c *Class1) Do() {
fmt.Println("Class1")
}
func init() {
// 在启动时注册类1的工厂
base.Register("Class1", func() base.Class {
return new (Class1)
})
}
$HOME/eight/8.5/clsfactory/cls2/reg.go
package cls2
import (
"../../../../eight/8.5/clsfactory/base"
"fmt"
)
// 定义类2
type Class2 struct {
}
// 实现Class接口
func (c *Class2) Do() {
fmt.Println("Class2")
}
func init() {
// 在启动时注册类1的工厂
base.Register("Class2", func() base.Class {
return new (Class2)
})
}
$HOME/eight/8.5/clsfactory/main.go
package main
import(
"../../../eight/8.5/clsfactory/base"
_ "../../../eight/8.5/clsfactory/cls1"
_ "../../../eight/8.5/clsfactory/cls2"
)
func main() {
// 根据字符串动态创建一个Class1的实例
c1 := base.Create("Class1")
c1.Do()
// 根据字符串动态创建一个Class2的实例
c2 := base.Create("Class2")
c2.Do()
}
运行结构:
Class1
Class2
原文地址:https://www.cnblogs.com/smallyi/p/12684478.html