欢迎光临
我们一直在努力

Go语言-4

一、包(package)

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

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

    package util

    func Hello() string {
    return "hello go"
    }

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

    别名导入:

    import u "yourProject/util"

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

  • init() 函数
    • 每个包可以有多个 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())

  • 空接口 interface{}
    没有任何方法,所有类型都默认实现空接口,可以接收任意数据。
  • func printAny(v interface{}) {
    fmt.Println(v)
    }

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

  • 类型断言
    从接口变量取出底层真实类型:
  • a := Animal(Dog{})
    if dogObj, ok := a.(Dog); ok {
    fmt.Println(dogObj)
    }

  • 类型判断 switch
  • 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{})
    }

    输出:

    汪汪
    喵喵

    关键点总结:

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

  • 接口接收值还是指针:
    • 如果方法是值接收者:值、指针都能赋值给接口。
    • 如果方法是指针接收者:只有指针实例可以赋值给接口,值实例不会实现接口。

    func (d *Dog) Speak() string { return "汪汪" }
    var a Animal
    // a = Dog{} // 报错,值类型没有实现接口
    a = &Dog{} // 正确

  • nil 接口坑:接口变量不等于 nil。接口内部动态类型不为 nil,就算值是 nil,接口本身不是 nil。
  • 包名建议小写,简洁;模块路径一般用仓库地址。
  • 接口尽量小,小接口设计原则,比如标准库 io.Reader 只有一个 Read 方法。
  • 赞(0)
    未经允许不得转载:171主机测评 » Go语言-4
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址