Golang语言基于GOPATH方式管理包(package)

简介: 这篇文章详细介绍了Golang语言中基于GOPATH方式管理包(package)的方法,包括包的概述、定义、引入格式、别名使用、匿名引入,以及如何快速入门自定义包,并通过具体代码案例展示了包的环境准备、代码编写、细节说明和程序运行。

                                              作者:尹正杰
版权声明:原创作品,谢绝转载!否则将追究法律责任。

一.包概述

1 为什么要使用包

使用包的原因主要有两个:
    - 1.我们不能把所有的函数都放在同一个源文件中,可以分门别类的把函数放在不同的源文件中;
    - 2.解决同名问题: 两个人想要定义一个同名的函数,在同一个文件中是不可以定义相同名字的函数,此时可以用包来区分;

Go语言中支持模块化的开发理念,在Go语言中使用包(package)来支持代码模块化和代码复用。

一个包是由一个或多个Go源码文件(.go结尾的文件)组成,是一种高级的代码复用方案,Go语言为我们提供了很多内置包,如fmt、os、io等。

2 包定义

我们可以根据自己的需要创建自定义包。一个包可以简单理解为一个存放"*.go"文件的文件夹。

该文件夹下面的所有"*.go"文件都要在非注释的第一行添加"package packagename"声明,声明该文件归属的包。
    - package:
        声明包的关键字。

    - packagename:
        包名,可以不与文件夹的名称一致,不能包含"-"符号,最好与其实现的功能相对应。

温馨提示:
    - 1.一个文件夹下面直接包含的文件只能归属一个包,同一个包的文件不能在多个文件夹下。
    - 2.包名为main的包是应用程序的入口包,这种包编译后会得到一个可执行文件,而编译不包含main包的源代码则不会得到可执行文件。

3 包的引入格式

要在当前包中使用另外一个包的内容就需要使用import关键字引入这个包,并且import语句通常放在文件的开头,package声明语句的下方。

完整的引入声明语句格式如下:
    import importname "path/to/package"

  其中:
    - import:
      引入包的关键字。

    - importname:
      引入的包名,通常都省略。默认值为引入包的包名。

    - path/to/package:
      引入包的路径名称,必须使用双引号包裹起来。


一个Go源码文件中可以同时引入多个包: 
    - 语法一:(一个Go源码文件中可以同时引入多个包)
import "fmt"
import "net/http"
import "os"


    - 语法二:(当然可以使用批量引入的方式)
import (
    "fmt"
    "net/http"
    "os"
)

4 包的别名

引入的多个包中存在相同的包名或者想自行为某个引入的包设置一个新包名时,都需要通过importname指定一个在当前文件中使用的新包名。例如,在引入fmt包时为其指定一个新包名f。

    - 导入时:
import f "fmt"

    - 使用时:
f.Println("Hello world!")

5 匿名引入

如果引入一个包的时候为其设置了一个特殊"_"作为包名,那么这个包的引入方式就称为匿名引入。

一个包被匿名引入的目的主要是为了加载这个包,从而使得这个包中的资源得以初始化。 

被匿名引入的包中的init函数将被执行并且仅执行一遍。举个例子:
    import _ "github.com/go-sql-driver/mysql"

匿名引入的包与其他方式导入的包一样都会被编译到可执行文件中。

需要注意的是,Go语言中不允许引入包却不在代码中使用这个包的内容,如果引入了未使用的包则会触发编译错误。

二.自定义包快速入门案例

1 包的环境准备

1.1 包的组织结构及环境声明

如上图所示,我的代码组织结构如上图所示。


本案例我定义的GOPATH环境变量为"GOPATH='/Users/yinzhengjie/golang/gosubjects'"

1.2 配置GO111MODULE

此处我想要使用GOPATH的方式导入包,则需要临时设置GO111MODULE的值为auto或者off
            go env -w GO111MODULE=auto

要启用go module支持首先要设置环境变量GO111MODULE,通过它可以开启或关闭模块支持,它有三个可选值:off、on、auto。
        GO111MODULE=off:
                禁用模块支持,编译时会从GOPATH和vendor文件夹中查找包。
        GO111MODULE=on:
                启用模块支持,编译时会忽略GOPATH和vendor文件夹,只根据 go.mod下载依赖。
        GO111MODULE=auto:
                当项目在$GOPATH/src外且项目根目录有go.mod文件时,开启模块支持。

2 db文件夹代码

2.1 haha.go代码

// 注意,包名称可以和文件夹不同名称哟~
package dbutils

import "fmt"


// 首字母大写,外部的包可以访问该函数
func Haha(){
    fmt.Println("in db package .... Haha")
}

// 首字母小写,外部的包不可以访问该函数,但内部同一个包是可以相互访问的。
func hehe(){
    fmt.Println("in db package .... hehe")
}

2.2 xixi.go代码

// 注意,包名称可以和文件夹不同名称哟~
package dbutils

import "fmt"

// 标识符首字母大写,可以被其他包访问
func GetConn() {
    fmt.Println("in db package .... getConn")
}

func Xixi(){
    fmt.Println("in db package .... Xixi start")

    // 同一个包的函数是可以相互访问的,尽管首字母是小写的
    hehe()

    fmt.Println("in db package .... Xixi end")
}

3 utils文件夹代码

3.1 haha.go代码

package utils

import (
    "fmt"
)

func Haha(){
    fmt.Println("in utils package .... Haha ")
}

3.2 xixi.go代码

package utils

import "fmt"

func Add(){
    fmt.Println("in utils package .... Add")
}

func Xixi(){
    fmt.Println("in utils package .... Xixi")
}

4 main包代码

/*
1.package用于进行包的声明,推荐包的声明和这个包所在的文件夹同名;
2.main包是程序的入口包,一般main函数会放在这个包下;
*/
package main

/*
    1.导包的包名是从"$GOPATH/src/"后开始计算的,使用"/"进行路径分隔;
    2.导包路径不推荐使用中文;
    3.如果有多个包建议一次性导入,当然你也可以使用"import"关键字逐行导入每个包;
*/
import (
    "fmt"
    // 此处导入的包是包所在的文件夹,但是使用包的时候不是db,而是dbutils哟~
    "gocode/devops/05-package/01-oa/db"
    // 此处我们也可以给包起别名,一旦起别名,则原来名为utils则不可以使用了,而是使用别名调用。
    yinzhengjie "gocode/devops/05-package/01-oa/utils"
)

func main() {
    fmt.Println("in main package ... main")

    // 在函数调用的时候前面要定位到所在的包
    dbutils.GetConn()
    dbutils.Xixi()
    dbutils.Haha()

    // 注意,无法调用hehe函数,因为该函数并不对外哟~如果想要访问,则需要将其首字母大写哟~
    // dbutils.hehe()

    // 注意,由于我上面在导入包的时候使用了别名技术,因此不能直接使用utils,而是使用别名yinzhengjie进行调用
    // utils.Xixi()
    // utils.Haha()
    // utils.Add()

    yinzhengjie.Xixi()
    yinzhengjie.Haha()
    yinzhengjie.Add()
}

5 运行程序

如上图所示,直接执行"go run main.go"就可以看到测试结果啦~

三.包的细节说明

- 1.package用于进行包的声明,推荐包的声明和这个包所在的文件夹同名;

- 2.main包是程序的入口包,一般main函数会放在这个包下;

- 3.包定义语法为"package packagename";

- 4.导包的语法为"import packagename",导包的包名是从"$GOPATH/src/"后开始计算的,使用"/"进行路径分隔;

- 5.导包路径不推荐使用中文;

- 6.如果有多个包建议一次性导入,当然你也可以使用"import"关键字逐行导入每个包;

- 7.函数名,变量名,常亮名称等标识符首字母大写,这些标识符才可以被其他包访问,否则小写的标识符不能被其他包访问;

- 8.一个目录下不能有重复的函数;

- 9.包名和文件夹的名字,可以不一样,但是导包是必须时文件夹的路径,调用时使用包名称即可;

- 10.一个目录下的同级文件归属于一个包,换句话说,就是同一个目录下的"*.go"源代码文件不能同时声明是隶属于多个包,必须统一;

- 11.包在程序层面上是使用相同"package packagename"的源文件组成的代码模块,在源文件层面就是一个文件夹;

- 12.可以给包取别名,取别名后,原来的包名就不能使用了;

- 13.如果引入一个包的时候为其设置了一个特殊"_"作为包名,那么这个包的引入方式就称为匿名引入。

- 14.Go语言中禁止循环导入包;
目录
相关文章
|
14天前
|
Go
Golang语言之管道channel快速入门篇
这篇文章是关于Go语言中管道(channel)的快速入门教程,涵盖了管道的基本使用、有缓冲和无缓冲管道的区别、管道的关闭、遍历、协程和管道的协同工作、单向通道的使用以及select多路复用的详细案例和解释。
47 4
Golang语言之管道channel快速入门篇
|
14天前
|
Go
Golang语言文件操作快速入门篇
这篇文章是关于Go语言文件操作快速入门的教程,涵盖了文件的读取、写入、复制操作以及使用标准库中的ioutil、bufio、os等包进行文件操作的详细案例。
37 4
Golang语言文件操作快速入门篇
|
14天前
|
Go
Golang语言之gRPC程序设计示例
这篇文章是关于Golang语言使用gRPC进行程序设计的详细教程,涵盖了RPC协议的介绍、gRPC环境的搭建、Protocol Buffers的使用、gRPC服务的编写和通信示例。
42 3
Golang语言之gRPC程序设计示例
|
14天前
|
安全 Go
Golang语言goroutine协程并发安全及锁机制
这篇文章是关于Go语言中多协程操作同一数据问题、互斥锁Mutex和读写互斥锁RWMutex的详细介绍及使用案例,涵盖了如何使用这些同步原语来解决并发访问共享资源时的数据安全问题。
37 4
|
14天前
|
Go 调度
Golang语言goroutine协程篇
这篇文章是关于Go语言goroutine协程的详细教程,涵盖了并发编程的常见术语、goroutine的创建和调度、使用sync.WaitGroup控制协程退出以及如何通过GOMAXPROCS设置程序并发时占用的CPU逻辑核心数。
23 4
Golang语言goroutine协程篇
|
14天前
|
Prometheus Cloud Native Go
Golang语言之Prometheus的日志模块使用案例
这篇文章是关于如何在Golang语言项目中使用Prometheus的日志模块的案例,包括源代码编写、编译和测试步骤。
20 3
Golang语言之Prometheus的日志模块使用案例
|
14天前
|
JSON Go 数据格式
Golang语言结构体链式编程与JSON序列化
这篇文章是关于Go语言中结构体链式编程与JSON序列化的教程,详细介绍了JSON格式的基本概念、结构体的序列化与反序列化、结构体标签的使用以及如何实现链式编程。
21 4
|
14天前
|
Go
Golang语言错误处理机制
这篇文章是关于Golang语言错误处理机制的教程,介绍了使用defer结合recover捕获错误、基于errors.New自定义错误以及使用panic抛出自定义错误的方法。
36 3
|
14天前
|
Go
Golang语言之函数(func)进阶篇
这篇文章是关于Golang语言中函数高级用法的教程,涵盖了初始化函数、匿名函数、闭包函数、高阶函数、defer关键字以及系统函数的使用和案例。
16 3
Golang语言之函数(func)进阶篇
|
14天前
|
Go
Golang语言之函数(func)基础篇
这篇文章深入讲解了Golang语言中函数的定义和使用,包括函数的引入原因、使用细节、定义语法,并通过多个案例展示了如何定义不返回任何参数、返回一个或多个参数、返回值命名、可变参数的函数,同时探讨了函数默认值传递、指针传递、函数作为变量和参数、自定义数据类型以及返回值为切片类型的函数。
17 2
Golang语言之函数(func)基础篇