go package包的使用以及路径问题

前言

一开始学 Go,非常晕的就是 package 包的问题,我们知道 Go 有一个很简单的文件可见性规则:首字母大写即对外可见,但是不知道对外是对什么外。
以及我在一个 ch1 目录下,创建一个 demo.go 文件,在输入 package 时, VS 又会自动提示 package ch1,这个和 main 又有什么关系呢?
我在一个 ch1 目录下写了一个 demo.go 文件,里面有一个函数,我在 ch2/demo2.go 里面想用又该怎么 import 呢?
带着这些疑问,这次来系统的了解一下~

Go的环境变量

在我们安装完 go 之后,输入

go env

会输出一大堆信息,其中 GOPATH 就是我们的工作区,我们写了一个 demo.go 文件,其中如果 import 了一些第三方库,运行的时候就会先从 GOROOT 中找,如果没有找到会再去 GOPATH 里面找
我们可以通过修改 GOPATH 添加额外的工作区,在你的 .zshrc / .bash_profile 文件里面

export GOPATH="/Users/lijun/go:/Users/lijun/Documents/Go/golearning"

引入第三方库

一般我们通过

go get -u github.com/julienschmidt/httprouter

这个指令下载的第三方库都会保存在 GOPATH 第一个工作区指定的 src 目录下
只需要在项目里

import "github.com/julienschmidt/httprouter"

就能使用这个第三方包了

有时候 go get 下载失败,可以手动去 GitHub 下载源代码,放到对应目录下,记住路径要和 GitHub 上的文件路径一致

在当前文件使用另一个文件定义的函数或变量

  • 同级目录
    在class文件夹下新建 demo.go 和 demo_lib.go
// demo_lib.go
package main

import "fmt"

func hello(name string) {
    fmt.Printf("Hello, %s!\n", name)
}
// demo.go
package main

import "flag"

var name string

func init() {
    flag.StringVar(&name, "name", "everyone", "The greeting object.")
}

func main() {
    flag.Parse()
    hello(name)
}

当在一个同级目录下面,有一个 package main 实现了 main() 函数的时候,这是作为程序的唯一入口。在同级目录下,别的文件也必须 package main,且不能再实现 main() 函数,否则提示 redeclared 错误。
此时 demo_lib.go 文件里的变量和函数对 demo.go 都是可见的。且不受可见性影响

  • 不同级目录
    现在我们在 class 文件夹下新建 lib 文件夹,在新建一个 demo2_lib.go 文件,demo2_lib 现在就有两种可能了
    1. package main 并且实现 main() 函数,那么它就是另一个新程序的入口了,内部的函数和变量就不能被别的文件 import
    2. package 包名,这样的话是可以被外部使用,但是我们需要把首字母大写,对外部可见(这里了解了对外部是指对别的包而言),我们现在测试这种情况
package lib

import "fmt"

func Hello(name string) {
    fmt.Println("Hello, %s!\n",)
}

如果 demo.go 要使用 demo2_lib 下的 Hello 函数,需要导入这个包。这时候我们需要 go install 一下

go install class/lib

后面的路径是要导入的包的相对路径,执行完之后,会在我们的工作区下生成 pkg/darwin_amd64/class/lib.a


2019-08-21-11.png

在 demo.go 导入即可

package main

import (
    "class/lib"
    "flag"
)

var name string

func init() {
    flag.StringVar(&name, "name", "everyone", "The greeting object.")
}

func main() {
    flag.Parse()
    lib.Hello(name)
}

到这里我们算是完成了一个供外部调用的包的程序

这里有个疑问

我在 class/lib 文件夹下创建的 demo2_lib.go 文件,并且 package lib,package的包名和所在文件夹名有必然联系吗?

// demo2_lib.go
package lib2

import "fmt"

func Hello(name string) {
    fmt.Printf("Hello, %s!\n", name)
}

改成 lib2 试一下
go install 后面跟的是路径,所以依然是 class/lib

go install class/lib

在主函数什么都不改变,调用

go run demo.go

此时提示

# command-line-arguments
./demo.go:4:2: imported and not used: "class2/lib" as lib2
./demo.go:18:2: undefined: lib

从字面上理解一下的话,第一个是说导入了但是没有把 class2/lib 当做 lib2 来使用,第二行说没有定义的 lib

emmm~~~

我记得 import 包的时候可以起个别名的,试一下

package main

import (
    lib2 "class/lib"
    "flag"
)

var name string

func init() {
    flag.StringVar(&name, "name", "everyone", "The greeting object.")
}

func main() {
    flag.Parse()
    lib2.Hello(name)
}

继续运行一下,输出结果

lijun:class2/ $ go run demo.go     
Hello, everyone!

可以了!!!
想一下,我们主要做了什么,和之前有什么不同
在路径 class/lib 下,demo2_lib.go 文件没有 package lib,而是 package lib2

// 原来
package lib

// 现在
package lib2

go install class/lib 这个步骤没有变也变不了。
最后在 main 函数中调用,原来是

import "class/lib"

lib.Hello(name)

现在是

import lib2 "class/lib"

lib2.Hello(name)

也就是说,当我们要在一个项目里新建一个 tool 文件夹放我们的工具包,我们可以不 package tool,而是可以写一个别的包名,依然可以使用,只不过在使用的时候,import 的还是 pkg 下的路径,但是要给这个 import 设置它真正的包名,即这里的 lib2

总结

算是弄明白了 Go 下的文件引用,以及 GOPATH 的设置。
同一级目录下只能有一个 main,且别的文件对它都是可见的,不需要设置大小写都可以被访问到,不同级目录,根据首字母大小写可见,还需要 go install一下,再 import 对应路径,包名可以和路径不一致,但是要设置别名。
简单了解后,如果还有别的疑惑欢迎大家一起探讨!

来自 https://leejnull.github.io/2019/08/21/2019-08-21-1/

你可能感兴趣的:(go package包的使用以及路径问题)