Go语言-4

一、包(package)

包是 Go 代码组织的最小单元,用来拆分功能、避免命名冲突。

  1. 包声明
    文件第一行 package xxx,声明当前文件属于哪个包。
  • package main:可执行程序,会生成二进制,必须有 func main() 入口函数。
  • 其他包(如 package util):库包,只提供功能,不能直接运行。
go 复制代码
package util

func Hello() string {
    return "hello go"
}
  1. 导出规则(大小写控制访问权限)
  • 大写开头:对外导出,其他包可以访问(函数、结构体、字段、常量)。
  • 小写开头:仅本包内可见,外部包无法访问。
  1. 导入包 import
go 复制代码
import (
    "fmt"
    "math/rand"
    "yourProject/util" // 导入自己写的包
)

别名导入:

go 复制代码
import u "yourProject/util"

匿名导入:只执行包 init 函数,不直接使用包内变量 import _ "github.com/xxx"

  1. init() 函数
  • 每个包可以有多个 init(),无参数无返回。
  • 执行时机:包被导入时自动执行,早于 main()
  • 执行顺序:依赖包 init → 当前包 init → main。

二、模块(module)

Go Module 是 Go 的依赖管理方案,go.mod 是模块描述文件,Go1.11+ 官方标准。

  1. 初始化模块
bash 复制代码
go mod init github.com/demo/myproj

生成 go.mod 文件:

复制代码
module github.com/demo/myproj

go 1.22
  • module:模块路径,也是 import 时的根路径。
  • go:声明最低兼容 Go 版本。
  1. go.sum

    依赖校验文件,记录第三方包哈希,保证依赖版本安全。不要手动修改。

  2. 常用命令

bash 复制代码
go mod tidy   # 自动整理依赖,增加缺失、删除未使用
go get xxx@v1.2.3 # 指定版本拉取依赖
go list -m all    # 查看全部依赖
  1. 模块下导入自己包
    项目结构:

    myproj/
    ├─ go.mod
    ├─ main.go
    └─ calc/
    └─ calc.go

go.mod 模块路径:github.com/demo/myproj

main.go 导入子包:

go 复制代码
import "github.com/demo/myproj/calc"

区分包与模块:模块是项目整体,包是模块内部的代码分组;一个模块可以包含多个包

三、接口 interface

Go 的接口是鸭子类型:不需要显式写 implements,只要类型拥有接口全部方法,就自动实现该接口。

  1. 接口定义
go 复制代码
type Animal interface {
    Speak() string
}

接口只定义方法签名,不写实现逻辑,没有函数体。

  1. 类型隐式实现接口
    只要结构体拥有接口里全部方法,就自动实现接口,不需要任何关键字。
go 复制代码
type Dog struct{}
func (d Dog) Speak() string {
    return "汪汪"
}

type Cat struct{}
func (c Cat) Speak() string {
    return "喵喵"
}

Dog、Cat 都实现了 Animal 接口。

  1. 接口变量
    接口变量可以存储任意实现该接口的类型实例。
go 复制代码
var a Animal
a = Dog{}
fmt.Println(a.Speak())

a = Cat{}
fmt.Println(a.Speak())
  1. 空接口 interface{}
    没有任何方法,所有类型都默认实现空接口,可以接收任意数据。
go 复制代码
func printAny(v interface{}) {
    fmt.Println(v)
}

Go1.18 之后推荐 any,等价于 interface{}

  1. 类型断言
    从接口变量取出底层真实类型:
go 复制代码
a := Animal(Dog{})
if dogObj, ok := a.(Dog); ok {
    fmt.Println(dogObj)
}
  1. 类型判断 switch
go 复制代码
switch v := a.(type) {
case Dog:
    fmt.Println("是狗", v)
case Cat:
    fmt.Println("是猫", v)
default:
    fmt.Println("未知类型")
}
  1. 接口嵌套
    接口可以组合其他接口,类似继承效果:
go 复制代码
type Runner interface {
    Run()
}
type Eater interface {
    Eat()
}
type Animal2 interface {
    Runner
    Eater
}

四、Go 的多态

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{})
}

输出:

复制代码
汪汪
喵喵

关键点总结:

  1. 同一个接口 Animal,传入 Dog / Cat,调用同一个 Speak(),行为不一样,就是多态。
  2. Go 多态是基于接口+鸭子类型,不是类继承。
  3. 接口变量保存:动态类型 + 动态值。编译只校验接口方法,运行时才确定真实类型。

五、注意

  1. 接口接收值还是指针:
  • 如果方法是值接收者:值、指针都能赋值给接口。
  • 如果方法是指针接收者:只有指针实例可以赋值给接口,值实例不会实现接口。
go 复制代码
func (d *Dog) Speak() string { return "汪汪" }
var a Animal
// a = Dog{} // 报错,值类型没有实现接口
a = &Dog{} // 正确
  1. nil 接口坑:接口变量不等于 nil。接口内部动态类型不为 nil,就算值是 nil,接口本身不是 nil。
  2. 包名建议小写,简洁;模块路径一般用仓库地址。
  3. 接口尽量小,小接口设计原则,比如标准库 io.Reader 只有一个 Read 方法。
相关推荐
泡海椒1 小时前
jquick-pdf 表格行列尺寸控制实战:单元格合并的可行边界
java·开发语言·pdf
纪念 2292 小时前
c++类和对象(四)
开发语言·c++
辛苦才能3 小时前
C++多态原理:虚函数表的内存布局与动态绑定的汇编真相
开发语言·c++
铲灰3 小时前
做个总结而已
开发语言
IvanCodes3 小时前
Python 文件操作(十二):文件与目录的读写
开发语言·python
神仙别闹11 小时前
基于 C++ 实现(控制台)学生成绩管理系统
开发语言·c++
伞伞悦读11 小时前
【第36期】Python 目录与路径详解:pathlib、文件遍历、创建、复制、移动和删除风险
开发语言·python
名字还没想好☜13 小时前
Go context.AfterFunc 实战(Go 1.21):context 一取消就自动跑清理,告别手写 goroutine 监听 Done
后端·golang·go
web守墓人13 小时前
【goed/ui】自定义组件设计思想篇
linux·windows·ui·golang