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 方法。
相关推荐
bkspiderx41 分钟前
Qt 插件机制:动态扩展应用功能的核心框架
开发语言·qt·元数据·qt 插件·qpluginloader
程序员老陆1 小时前
深入理解 C++ thread_local:线程私有存储的正确打开方式
开发语言·c++·程序设计
沐晓时光1 小时前
C语言入门,深入理解指针(3)
c语言·开发语言
码云数智-园园1 小时前
unique_ptr 还是 shared_ptr?C++ 智能指针选型与内存泄漏实战分析
java·开发语言
禾小西2 小时前
07丨Redis 哨兵机制:主库故障后,如何恢复服务?
java·开发语言·redis
我不是阵雨2 小时前
JDK 21虚拟线程Pinning陷阱:一文拔钉解困
java·开发语言
徐小黑ACG3 小时前
Golang 基础05 结构体struct
开发语言·算法·golang
优橙教育3 小时前
零基础学AI应用开发要多久?3个月能到什么水平
服务器·开发语言·网络·php
SEO_juper4 小时前
用 Python 写一个 GEO 可见性检查脚本:你的网站现在能被 AI 引用吗
开发语言·人工智能·爬虫·python·seo·外贸独立站
西柚小萌新4 小时前
【LLM&&AI应用开发 八股文】--4.3.Agent智能体(下)
java·开发语言·数据库