一、包(package)
包是 Go 代码组织的最小单元,用来拆分功能、避免命名冲突。
文件第一行 package xxx,声明当前文件属于哪个包。
- package main:可执行程序,会生成二进制,必须有 func main() 入口函数。
- 其他包(如 package util):库包,只提供功能,不能直接运行。
package util
func Hello() string {
return "hello go"
}
- 大写开头:对外导出,其他包可以访问(函数、结构体、字段、常量)。
- 小写开头:仅本包内可见,外部包无法访问。
import (
"fmt"
"math/rand"
"yourProject/util" // 导入自己写的包
)
别名导入:
import u "yourProject/util"
匿名导入:只执行包 init 函数,不直接使用包内变量 import _ "github.com/xxx"
- 每个包可以有多个 init(),无参数无返回。
- 执行时机:包被导入时自动执行,早于 main()。
- 执行顺序:依赖包 init → 当前包 init → main。
二、模块(module)
Go Module 是 Go 的依赖管理方案,go.mod 是模块描述文件,Go1.11+ 官方标准。
go mod init github.com/demo/myproj
生成 go.mod 文件:
module github.com/demo/myproj
go 1.22
- module:模块路径,也是 import 时的根路径。
- go:声明最低兼容 Go 版本。
go.sum
依赖校验文件,记录第三方包哈希,保证依赖版本安全。不要手动修改。
常用命令
go mod tidy # 自动整理依赖,增加缺失、删除未使用
go get xxx@v1.2.3 # 指定版本拉取依赖
go list -m all # 查看全部依赖
项目结构:
myproj/
├─ go.mod
├─ main.go
└─ calc/
└─ calc.go
go.mod 模块路径:github.com/demo/myproj
main.go 导入子包:
import "github.com/demo/myproj/calc"
区分包与模块:模块是项目整体,包是模块内部的代码分组;一个模块可以包含多个包。
三、接口 interface
Go 的接口是鸭子类型:不需要显式写 implements,只要类型拥有接口全部方法,就自动实现该接口。
type Animal interface {
Speak() string
}
接口只定义方法签名,不写实现逻辑,没有函数体。
只要结构体拥有接口里全部方法,就自动实现接口,不需要任何关键字。
type Dog struct{}
func (d Dog) Speak() string {
return "汪汪"
}
type Cat struct{}
func (c Cat) Speak() string {
return "喵喵"
}
Dog、Cat 都实现了 Animal 接口。
接口变量可以存储任意实现该接口的类型实例。
var a Animal
a = Dog{}
fmt.Println(a.Speak())
a = Cat{}
fmt.Println(a.Speak())
没有任何方法,所有类型都默认实现空接口,可以接收任意数据。
func printAny(v interface{}) {
fmt.Println(v)
}
Go1.18 之后推荐 any,等价于 interface{}。
从接口变量取出底层真实类型:
a := Animal(Dog{})
if dogObj, ok := a.(Dog); ok {
fmt.Println(dogObj)
}
switch v := a.(type) {
case Dog:
fmt.Println("是狗", v)
case Cat:
fmt.Println("是猫", v)
default:
fmt.Println("未知类型")
}
接口可以组合其他接口,类似继承效果:
type Runner interface {
Run()
}
type Eater interface {
Eat()
}
type Animal2 interface {
Runner
Eater
}
四、Go 的多态
Go 没有类继承,依靠接口实现多态。 多态:同一个接口,不同底层类型,调用同一个方法表现不同行为。
完整示例:
package main
import "fmt"
type Animal interface {
Speak() string
}
type Dog struct{}
func (d Dog) Speak() string { return "汪汪" }
type Cat struct{}
func (c Cat) Speak() string { return "喵喵" }
// 接收接口类型,兼容所有实现类
func MakeSound(a Animal) {
fmt.Println(a.Speak())
}
func main() {
MakeSound(Dog{})
MakeSound(Cat{})
}
输出:
汪汪
喵喵
关键点总结:
五、注意
- 如果方法是值接收者:值、指针都能赋值给接口。
- 如果方法是指针接收者:只有指针实例可以赋值给接口,值实例不会实现接口。
func (d *Dog) Speak() string { return "汪汪" }
var a Animal
// a = Dog{} // 报错,值类型没有实现接口
a = &Dog{} // 正确






