Go语言--第8章 包(package)

第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

  1. 设置当前工作目录为GOPATH
  2. 建立GOPATH中源码目录
  3. 添加main.go源码文件
  4. 编译源码并运行

以下示例为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默认导入写法

  1. 单行导入

    import "包1"
    import "包2"
    
  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

时间: 2024-10-17 03:33:18

Go语言--第8章 包(package)的相关文章

Lua中的模块(module)和包(package)详解1

这篇文章主要介绍了Lua中的模块(module)和包(package)详解,本文讲解了require函数.写一个模块.package.loaded.module函数等内容,需要的朋友可以参考下 前言 从Lua5.1版本开始,就对模块和包添加了新的支持,可是使用require和module来定义和使用模块和包.require用于使用模块,module用于创建模块.简单的说,一个模块就是一个程序库,可以通过require来加载.然后便得到了一个全局变量,表示一个table.这个table就像是一个命

Lua中的模块(module)和包(package)详解

这篇文章主要介绍了Lua中的模块(module)和包(package)详解,本文讲解了require函数.写一个模块.package.loaded.module函数等内容,需要的朋友可以参考下 前言 从Lua5.1版本开始,就对模块和包添加了新的支持,可是使用require和module来定义和使用模块和包.require用于使用模块,module用于创建模块.简单的说,一个模块就是一个程序库,可以通过require来加载.然后便得到了一个全局变量,表示一个table.这个table就像是一个命

JAVA中包(package)的使用

暑假荒废了个把月,不过还是值得的,毕竟学会了游泳!好了,言归正传,由于JAVA中的文件是按类组织的,因此经常会用到包(package)的概念,下面举例子说明. JAVA是面向对象的语言,程序都是以类(class)为最小单位的,所有的程序都必须放在类定义里.JAVA源文件的后缀必须是 .java,通常JAVA程序源文件的主文件名可以是任意的,但如果JAVA程序源代码里定义了一个public类,则主文件名必须与该类相同,一般类名的首字母习惯大写.通常的习惯是每个源文件中只定义一个类,不同的类使用不同

go语言碎片整理之包

在工程化的Go语言开发项目中,Go语言的源码复用是建立在包(package)基础之上的,本文介绍了go语言中如何定义包,如何导出包的内容以及如何导入其他包. 包介绍 包(package)是多个Go源码的集合,是一种高级的代码复用方案,go语言为我们提供了很多的内置包,如fmt.os.io等. 定义包 我们还可以根据自己的需要创建自己的包,一个包可以简单理解为一个存放.go文件的文件夹.该文件夹下面的所有go文件都要在代码的第一行添加如下代码,声明该文件归属包. package 包名 注意事项:1

编写第一个ROS(创建工作空间workspace和功能包package)

刚接触ROS,学着写了第一个程序,怕以后忘记,就将其步骤记录下来.. 首先你必须保证你电脑已安装配置好ROS. 1.创建工作空间(workspace) 我们所创建功能包package,应该全部放到一个叫做工作空间(workspace)的目录中 .你可以把目录存储在你账号的任何位置例如,我所创建的工作空间的是路径/home,同时你可以用任何你喜欢的名字命名你的工作空间,我的工作空间名为 test,现在请使用标准的mkdir命令行去创建一个工作空间.我首先建立一个工作空间,名字为test, 此处创建

项目工程的包package与文件夹的关系

项目工程的包package与文件夹的关系: 1. 包名与文件夹是分层关系,包名只是一个字符串而已,包名.对应的是层级的文件夹. 如,com.Immoc.Access包,只是一个字符串.但他对应的windows存储文件夹层级关系则是,src/com/Imooc/Access多个文件夹.

plsql的程序包package

9. 程序包--PACKAGE 9.1 包的定义和编译 包:一个PLSQL相关对象的逻辑分组和单个对象存储在数据库对象中的数据单元.相关的PLSQL对象包括:常量.变量.游标.异常.SP.FUN 包由两部分组成: 规范部分(包头.调用接口)  +  主体部分(包体.实现部分) (1) 包头的创建: create or replace package org_Master is     max_sites_for_an_org number;    type rc is ref cursor;  

c语言程序设计第一章3

字符数组是C语言中最常用的数组类型.下面我们通过编写一个程序,来说明字符数组以反操作字符数组的函数的用法.该程序读入一组文本行,并把最长的文水行打印出来.该算法的基本框架非常简单: while (还有未处理的行) i f (该行比已处理的最长行还要长) 保存该行 保存该行的长度 打印最长的行 1 #include <stdio.h> 2 #include <stdlib.h> 3 #define MAXLENGTH 100//文本的最大长度 4 int getline(char l

Swift 1.1语言第7章 函数和闭包

Swift 1.1语言第7章  函数和闭包 在编程中,随着处理问题的越来越复杂,代码量飞速增加.其中,大量的代码往往相互重复或者近似重复.如果不采有效方式加以解决,代码将很难维护.为 了解决这个问题,人们提出了函数这一概念.使用函数可以将特定功能的代码封装,然后在很多的地方进行使用.本章将会讲解函数和闭包的相关内容.本文选自<Swift 1.1语言快速入门> 7.1  函数介绍 函数是执行特定任务的代码块.使用函数会给开发这带来很多的好处.以下总结了其中两点. 1.结构鲜明,便于理解 如果在一