go语言学习之包和依赖管理

文章目录

  • package
    • package简单说明及示例
    • package 中init方法
    • 如何使用第三方package
  • 依赖管理
    • vendor 路径
    • 常用的依赖管理工具
    • 演示 glide 依赖管理工具

package

package简单说明及示例

go 语言中 package 的特点

  1. 基本复用模块单元 以首字母大写来表明可被包外代码访问
  2. 代码的 package 可以和所在的目录不⼀致(在 Java 中目录名和包名总是保持一致)
  3. 同一目录里的 Go 代码的 package 要保持⼀致

示例

在 ch8 这个 directory 下再新建一个 client directory 和一个 series directory,my_series.go 文件中是一个求 Fibonacci 数列的函数。
go语言学习之包和依赖管理_第1张图片
my_series.go

package series

import "errors"

// 获取 fibonacci 数列,首字母大写表示可以在包外被访问
// 如果是 getFibonacci 则无法被包外访问
func GetFibonacci(n int) ([]int, error) {
	if n <= 1 || n >= 100 {
		return nil, errors.New("the input num n is illegal")
	}
	prev, last := 1, 2
	fibList := []int{1, 2}
	for i := 3; i <= n; i++ {
		var tmp = prev + last
		fibList = append(fibList, tmp)
		//同时赋值,将last的值赋值给prev,将tmp的值赋值给last
		prev, last = last, tmp
	}
	return fibList, nil
}

package_test.go

package client

import (
	"ch8/series"
	"testing"
)

func TestPackageManagement(t *testing.T) {
	if fibList, err := series.GetFibonacci(5); err == nil {
		t.Log(fibList)
		return
	} else {
		t.Log(fibList)
	}
}

控制台输出

=== RUN   TestPackageManagement
    package_test.go:10: [1 2 3 5 8]
--- PASS: TestPackageManagement (0.00s)
PASS

如果我们将 my_series.go 中的 GetFibonacci 修改为 getFibonacci
就会发现无法访问 getFibonacci 方法
go语言学习之包和依赖管理_第2张图片
如果又修改为 GetFibonacci,就可以发现又可以开始访问了
go语言学习之包和依赖管理_第3张图片

如下时运行时遇到的问题:package xxx is not in GOROOT,按照如下方法即可解决

package ch8/client is not in GOROOT (C:\Program Files\Go\src\ch8\client)
  1. 设置工程的 GOPATH
    go语言学习之包和依赖管理_第4张图片
  2. 设置 go 的环境变量 GO111MODULE=off
go env -w GO111MODULE=off

可以通过 go env 命令查看环境变量是否修改成功
go语言学习之包和依赖管理_第5张图片

package 中init方法

  • 在 main 被执行前,所有依赖的 package 的 init 方法都会被执行
  • 不同包的 init 函数按照包导入的依赖关系决定执行顺序(包与包之间存在依赖顺序,这个是由go来帮我们完成)
  • 每个包可以有多个 init 函数(允许存在方法签名完全相同的 init 函数,一般来说代码中不允许存在方法签名完全相同的两个方法,但在go中init方法是个例外,另外补充一下,在go语言中不支持方法重载,不允许方法的方法名相同,即便方法签名不同)
  • 包的每个源文件也可以有多个 init 函数

如下所示,我在 my_series.go 添加了两个 init 方法,这两个 init。

package series

import (
	"errors"
	"fmt"
)

func init() {
	fmt.Println("执行init方法1")
}

func init() {
	fmt.Println("执行init方法2")
}

// 获取 fibonacci 数列,首字母大写表示可以在包外被访问
// 如果是 getFibonacci 则无法被包外访问
func GetFibonacci(n int) ([]int, error) {

	if n <= 1 || n >= 100 {
		return nil, errors.New("the input num n is illegal")
	}
	prev, last := 1, 2
	fibList := []int{1, 2}
	for i := 3; i <= n; i++ {
		var tmp = prev + last
		fibList = append(fibList, tmp)
		//同时赋值,将last的值赋值给prev,将tmp的值赋值给last
		prev, last = last, tmp
	}
	return fibList, nil
}

进行调用

package client

import (
	"ch8/series"
	"testing"
)

func TestPackageManagement(t *testing.T) {
	if fibList, err := series.GetFibonacci(5); err == nil {
		t.Log(fibList)
		return
	} else {
		t.Log(fibList)
	}
}

从输出中可以看到,两个init方法都被执行了,按照定义的先后顺序进行执行。

执行init方法1
执行init方法2
=== RUN   TestPackageManagement
    package_test.go:10: [1 2 3 5 8]
--- PASS: TestPackageManagement (0.00s)
PASS

如何使用第三方package

比如这里有一个第三方package,这是一个 concurrent_map,github地址为:https://github.com/easierway/concurrent_map

由于 github 访问速度太慢,我将其导入到我的 gitee 仓库中。
地址为:https://gitee.com/simonzhaojia/concurrent_map.git

从该仓库中我们可以看出只有 package 的源码,没有 src 等路径,我们提交代码到 git 仓库时,也应该只提交 package 的源码,不要将 src 的路径也提交上去,这样就可以通过 go get 命令获取到。
go语言学习之包和依赖管理_第6张图片

首先看看我的工程目录,可以发现此时的 src 路径还没有第三方package。
go语言学习之包和依赖管理_第7张图片
然后我在windows 的 terminal 中执行如下命令,需要注意的是,在命令行中执行命令时,一定要到工程的目录下去执行。

D:\dev\go\go_learning>go get -u gitee.com/simonzhaojia/concurrent_map

D:\dev\go\go_learning>

-u 参数表示每次导入时都需要从网上去检查最新版,有最新版就更新。地址没有以 https:// 开头,直接以域名开头,也不需要地址最后以 .git 结尾。

执行完毕以后就会发现在工程目录下多了一个文件夹,里面就是导入的第三方 package
go语言学习之包和依赖管理_第8张图片
使用

package remote_package

import (
	// cm 是给import的package 起的一个别名
	cm "gitee.com/simonzhaojia/concurrent_map"
	"testing"
)
func TestConcurrentMap(t *testing.T) {
	m := cm.CreateConcurrentMap(99)
	m.Set(cm.StrKey("key1"), 10)
	if value , ok := m.Get(cm.StrKey("key1")); ok {
		t.Logf("value = %d",value)
	}
}

输出

=== RUN   TestConcurrentMap
    remote_package_test.go:12: value = 10
--- PASS: TestConcurrentMap (0.00s)
PASS

依赖管理

go 依赖的问题。在依赖管理方面,go 还不如Java成熟,在Java中可以使用 Maven 和 Gradle 来进行依赖管理。

  • 同一环境下,不同项目使用同⼀包的不同版本(最初的时候Go语言所依赖的所有的第三方包都放在 GOPATH 目录下面,这就导致了同一个包只能保存一个版本的代码。go module 是Go语言从 1.11 版本之后官方推出的版本管理工具,并且从 Go1.13 版本开始,go module 成为了Go语言默认的依赖管理工具)
  • 无法管理对包的特定版本的依赖

vendor 路径

演示 go 语言中的依赖管理之前,先了解一下 go 中的 vendor 路径。

Go语言从 1.5 版本开始开始引入 vendor 模式,如果项目目录下有 vendor 目录,那么Go语言编译器会优先使用 vendor 内的包进行编译、测试等。

常用的依赖管理工具

go 语言中常用的依赖管理工具

  • godep https://github.com/tools/godep
  • glide https://github.com/Masterminds/glide
  • dep https://github.com/golang/dep

在 go1.11时出现了 go module,官方推荐使用 go module 来进行依赖管理,go module 由于是新出来不久的,使用和实践也还比较少,更多的还是上面列举的工具。

演示 glide 依赖管理工具

如下,演示一下 glide 的使用。

首先是先安装 glide,可以参照如下教程。

Windows 下安装 Glide 的教程

在上述的例子中,我们在 remote_package 这个包中,使用了一个第三方的包 concurrent_map,如下演示如何使用 glide 管理 remote_package 这个包使用的第三方包。

package remote_package

import (
	// cm 是给import的package 起的一个别名
	cm "gitee.com/simonzhaojia/concurrent_map"
	"testing"
)
func TestConcurrentMap(t *testing.T) {
	m := cm.CreateConcurrentMap(99)
	m.Set(cm.StrKey("key1"), 10)
	if value , ok := m.Get(cm.StrKey("key1")); ok {
		t.Logf("value = %d",value)
	}
}

进入 remote_package 这个 package 所在的路径下执行 glide init,然后一路 Yes 下去。

D:\dev\go\go_learning\src\ch8\remote_package>glide init
[INFO]  Generating a YAML configuration file and guessing the dependencies
[INFO]  Attempting to import from other package managers (use --skip-import to skip)
[INFO]  Scanning code to look for dependencies
[INFO]  --> Found test reference to gitee.com\simonzhaojia\concurrent_map
[INFO]  Writing configuration file (glide.yaml)
[INFO]  Would you like Glide to help you find ways to improve your glide.yaml configuration?
[INFO]  If you want to revisit this step you can use the config-wizard command at any time.
[INFO]  Yes (Y) or No (N)?
Y
[INFO]  Looking for dependencies to make suggestions on
[INFO]  --> Scanning for dependencies not using version ranges
[INFO]  --> Scanning for dependencies using commit ids
[INFO]  Gathering information on each dependency
[INFO]  --> This may take a moment. Especially on a codebase with many dependencies
[INFO]  --> Gathering release information for dependencies
[INFO]  --> Looking for dependency imports where versions are commit ids
[INFO]  Here are some suggestions...
[INFO]  The package gitee.com/simonzhaojia/concurrent_map appears to have Semantic Version releases (http://semver.org).

[INFO]  The latest release is v1.0.0. You are currently not using a release. Would you like
[INFO]  to use this release? Yes (Y) or No (N)
Y
[INFO]  Would you like to remember the previous decision and apply it to future
[INFO]  dependencies? Yes (Y) or No (N)
Y
[INFO]  Updating gitee.com/simonzhaojia/concurrent_map to use the release v1.0.0 instead of no release
[INFO]  The package gitee.com/simonzhaojia/concurrent_map appears to use semantic versions (http://semver.org).
[INFO]  Would you like to track the latest minor or patch releases (major.minor.patch)?
[INFO]  Tracking minor version releases would use '>= 1.0.0, < 2.0.0' ('^1.0.0'). Tracking patch version
[INFO]  releases would use '>= 1.0.0, < 1.1.0' ('~1.0.0'). For more information on Glide versions
[INFO]  and ranges see https://glide.sh/docs/versions
[INFO]  Minor (M), Patch (P), or Skip Ranges (S)?
S
[INFO]  Would you like to remember the previous decision and apply it to future
[INFO]  dependencies? Yes (Y) or No (N)
Y
[INFO]  Configuration changes have been made. Would you like to write these
[INFO]  changes to your configuration file? Yes (Y) or No (N)
Y
[INFO]  Writing updates to configuration file (glide.yaml)
[INFO]  You can now edit the glide.yaml file.:
[INFO]  --> For more information on versions and ranges see https://glide.sh/docs/versions/
[INFO]  --> For details on additional metadata see https://glide.sh/docs/glide.yaml/

D:\dev\go\go_learning\src\ch8\remote_package>

执行完毕以后,可以发现在 remote_package 这个package 下生成了一个 glide.yaml
go语言学习之包和依赖管理_第9张图片
glide.yaml 中的内容如下。里面有 remote_package 这个package 所使用依赖的相应版本。

package: ch8/remote_package
import: []
testImport:
- package: gitee.com/simonzhaojia/concurrent_map
  version: v1.0.0

现在我将之前导入的依赖包删除掉
go语言学习之包和依赖管理_第10张图片
因为依赖包都被删除掉了,之前的代码自然就报错了。
go语言学习之包和依赖管理_第11张图片
然后在 remote_package 的路径下执行 glide install 命令,输出如下。

D:\dev\go\go_learning\src\ch8\remote_package>glide install
[INFO]  Lock file (glide.lock) does not exist. Performing update.
[INFO]  Downloading dependencies. Please wait...
[INFO]  --> Fetching gitee.com/simonzhaojia/concurrent_map.
[INFO]  --> Setting version for gitee.com/simonzhaojia/concurrent_map to v1.0.0.
[INFO]  Resolving imports
[INFO]  Downloading dependencies. Please wait...
[INFO]  Setting references for remaining imports
[INFO]  Exporting resolved dependencies...
[INFO]  --> Exporting gitee.com/simonzhaojia/concurrent_map
[INFO]  Replacing existing vendor dependencies
[INFO]  Project relies on 0 dependencies.

D:\dev\go\go_learning\src\ch8\remote_package>

可以发现在 remote_package 的路径下生成了一个 vendor 文件夹,里面下载了第三方的包(和之前使用 go get 命令下载第三方包的路径不同,go get 命令下载的第三方包在 src 路径下)。此时,verdor 路径已经添加到程序的扫描包的路径下,程序自然也没有报错了。
go语言学习之包和依赖管理_第12张图片

参考
Go语言从入门到实战 蔡超

你可能感兴趣的:(go,go,golang,git)