【Golang】模块管理与引用

Posted by 西维蜀黍 on 2020-03-15, Last Modified on 2023-02-23

包声明 - package

在go源文件的开头必须申明文件所属的package,如下所示:

package name
......

一些实验发现

实验 1

注意,位于同一个文件夹下的所有 .go 文件,它们的 package name 一定要完全一致。比如,由于 ccc.go 和 ddd.go 两个文件都位于 bbb 文件夹下,因此这两个文件的 package name 必需要完全一致(但这个 package name 不要求一定为 bbb,即不一定要和所在文件夹的文件夹名称相同)。

如果不一致,则会提示以下错误:

实验 2

一个正确的引用:

aaa/bbb/ccc.go

package cccPackageName

import "fmt"

func SayHello(name string) string {
	return fmt.Sprintf("Hello, %s", name)
}

main.go

package main

import "swtest/aaa/bbb"

func main()  {
	cccPackageName.SayHello("sss")
}

go.mod

module swtest

go 1.13

https://www.digitalocean.com/community/tutorials/how-to-write-packages-in-go

实验 3

结论:在同一个文件夹下的不同文件中的函数,它们在被 import 时,都是 equivalent 的。

aaa/bbb/ccc.go

package bbb

import "fmt"

func SayHello(name string) string {
	return fmt.Sprintf("Hello, %s", name)
}

aaa/bbb/ddd.go

package bbb

import "fmt"

func SayHello2(s string)  {
	fmt.Println(s)
}

main.go

package main

import (
	"awesomeProject/aaa/bbb"
)

func test()  {
	bbb.SayHello("test1")
	bbb.SayHello2("test2")
}

go.mod

module awesomeProject

go 1.13

命名规范

  • 建议package命名用小写字母
  • 建议package命名必和其路径的最后一段一致(main package除外)
  • main package中的main方法是可执行文件的入口,main package名可以和路径名不一致
  • 不同路径下package命名可以重复,但其完整路径名必须唯一

package 名和导入路径

package的导入路径是指从$GOPATH/src/开始的路径名。例如 package github.com/zhaohuabing/demo 在文件系统中的路径为:$GOPATH/src/github.com/zhaohuabing/demo

Import

package main

import (
	"fmt"
	"math/rand"
)

func main() {
	fmt.Println("My favorite number is", rand.Intn(10))
}

This program is using the packages with import paths "fmt" and "math/rand".

By convention, the package name is the same as the last element of the import path. For instance, the "math/rand" package comprises files that begin with the statement package rand.

代码第一行写明package;上例中,希望被执行的文件必须放在其起始处声明package main,否则在go run运行时会报错:”go run: cannot run non-main package“

Multiple Import Ways

常规方式

常规方式,通过包名lib调用sayHello方法.lib.SayHello()

import github.com/libragen/felix/lib

包名用""包裹,文件夹层次用/表示。

普通导入就是按照加载机制,将要使用的包导入进来,然后使用 packageName.MethodName 的方式调用包内的方法即可。注意如果要包方法在其他包中可以调用,包方法需要首字母大写,例如:fmt.Println()

别名导入

  • 包名过于复杂或者意思不明确. 如使用 mywebapp/libs/mongodb/db 包时,不确定此 db 是哪种类型,故可以使用别名来明确含义: import mongo "mywebapp/libs/mongodb/db"
  • 包名和其他包冲突:世界之大,变化无穷。现在我们有库 db,但没过几年出现了另一种DB,叫云DB。但包名是一样的,分别用别名区分:
import (
    "fmt"
    myBaz "foo/bar/baz"
    ydbgo "mywebapp/libs/yundb/db"
    mongo "mywebapp/libs/mongodb/db"
)

func main() {
    fmt.Println(myBaz.Hello(), myBaz.World())
}

如果两个包的包名存在冲突,或者包名太长需要简写时,我们可以使用别名导入来解决。

省略package名导入

这里的. 符号表示:在调用包 lib 的成员时,不需要再声明包名。

比如,Println() 是 fmt 包中的方法,在一般的情况下,我们都通过 fmt.Println() 来调用。而使用 . "fmt" 后,直接可以调 Println()

package main
import {
	. "github.com/libragen/felix/lib"
	. "fmt"
}
func main() {
	SayHello()
	Println("test")
}

下划线操作

package main

import (
    "fmt"
    _ "foo/bar/baz"
)

func main() {
    fmt.Println(baz.Hello(), baz.World()) // 错误 _ 并没有导入包 只是引入并执行包模块的 init  方法
}

_ 是包引用操作,只会执行包下各模块中的 init 方法,并不会真正的导入包,所以不可以调用包内的其他方法。

The access after import

a name is exported if it begins with a capital letter. For example, Pizza is an exported name, as is Pi, which is exported from the math package.

pizza and pi do not start with a capital letter, so they are not exported.

When importing a package, you can refer only to its exported names. Any “unexported” names are not accessible from outside the package.

package main

import (
	"fmt"
	"math"
)

func main() {
	fmt.Println(math.pi)
}

To fix the error, rename math.pi to math.Pi and try it again.