🏗️ 第05课:结构体与接口

Go基础 第1阶段·第5/7课

📋 本课目标

🔬 代码演示与验证

package main
import ("fmt";"math")
type User struct{ID int;Name string;Age int}
func (u User)Greet()string{return fmt.Sprintf("你好,%s,%d岁",u.Name,u.Age)}
func (u *User)Birthday(){u.Age++}
type Shape interface{Area()float64;Perimeter()float64}
type Circle struct{Radius float64}
func(c Circle)Area()float64{return math.Pi*c.Radius*c.Radius}
func(c Circle)Perimeter()float64{return 2*math.Pi*c.Radius}
type Rect struct{W,H float64}
func(r Rect)Area()float64{return r.W*r.H}
func(r Rect)Perimeter()float64{return 2*(r.W+r.H)}
func printInfo(s Shape){fmt.Printf("  %T: 面积=%.2f 周长=%.2f\n",s,s.Area(),s.Perimeter())}
type Animal struct{Name string}
func(a Animal)Speak()string{return a.Name+" 发出声音"}
type Dog struct{Animal;Breed string}
func(d Dog)Speak()string{return d.Name+" 汪汪汪!"}
func main() {
    u1:=User{ID:1,Name:"张三",Age:25}; fmt.Printf("用户:%+v\n",u1); fmt.Println(u1.Greet())
    u1.Birthday(); fmt.Printf("生日后:%+v\n",u1)
    u2:=&User{ID:2,Name:"李四",Age:30}; fmt.Println(u2.Greet())
    config:=struct{Host string;Port int}{Host:"localhost",Port:8080}; fmt.Printf("匿名:%+v\n",config)
    fmt.Println("\n=== 接口多态 ===")
    shapes:=[]Shape{Circle{Radius:5},Rect{W:3,H:4}}
    for _,s:=range shapes{printInfo(s)}
    fmt.Println("\n=== 类型断言 ===")
    var i interface{}="hello"
    if s,ok:=i.(string);ok{fmt.Printf("string:%s\n",s)}
    switch v:=i.(type){case int:fmt.Printf("int:%d\n",v);case string:fmt.Printf("str:%s\n",v)}
    fmt.Println("\n=== 嵌入 ===")
    d:=Dog{Animal:Animal{Name:"旺财"},Breed:"柯基"}; fmt.Println(d.Speak()); fmt.Println(d.Name)
}

🔍 运行验证

✅ 验证通过 — 实机运行结果:

用户:{ID:1 Name:张三 Age:25}
你好,张三,25岁
生日后:{ID:1 Name:张三 Age:26}
你好,李四,30岁
匿名:{Host:localhost Port:8080}

=== 接口多态 ===
  main.Circle: 面积=78.54 周长=31.42
  main.Rect: 面积=12.00 周长=14.00

=== 类型断言 ===
string:hello
str:hello

=== 嵌入 ===
旺财 汪汪汪!
旺财

🧠 Go OOP

组合优于继承 接口隐式实现(鸭子类型) 方法绑定到接收者类型 大小写可见性规则

⚙️ 接收者选择

场景选择
需修改指针
大结构体指针
一致性统一
基本类型

🔌 接口

type Shape interface { Area() float64 }
// 隐式实现:只要实现Area()就是Shape
type Circle struct { R float64 }
func (c Circle) Area() float64 { return math.Pi*c.R*c.R }

🔗 嵌入

type Animal struct { Name string }
type Dog struct { Animal; Breed string }  // 嵌入Animal
d := Dog{Animal: Animal{Name:"旺财"}, Breed:"柯基"}
fmt.Println(d.Name)  // 直接访问嵌入字段

🔑 本课要点回顾

知识点关键内容
结构体字段/标签/初始化
方法值vs指针接收者
接口隐式实现/多态
类型断言v,ok:=i.(Type)
嵌入组合优于继承

🏋️ 练习

银行卡

Deposit/Withdraw/Balance

sort.Interface

自定义排序

Logger接口

Console/File实现

🏆

成就解锁:面向对象大师!

📖 接口深入

接口值内部结构

// 接口值 = (type, value) 二元组
var s Shape = Circle{Radius: 5}
// s = (type: Circle, value: {Radius: 5})

// nil接口 vs 空值接口
var s1 Shape          // nil接口: (nil, nil)
var s2 Shape = (*User)(nil)  // 非nil: (*User, nil)
// s1 == nil → true
// s2 == nil → false ⚠️ 常见陷阱!

接口组合

type Reader interface { Read([]byte) (int, error) }
type Writer interface { Write([]byte) (int, error) }
type ReadWriter interface {
    Reader
    Writer
}

🏗️ 结构体标签实战

type User struct {
    ID       int    `json:"id" db:"user_id"`
    Name     string `json:"name" validate:"required"`
    Email    string `json:"email" validate:"email"`
    Age      int    `json:"age,omitempty"`
    Password string `json:"-"`  // JSON中忽略
}

// 用reflect读取标签
t := reflect.TypeOf(User{})
field, _ := t.FieldByName("Name")
fmt.Println(field.Tag.Get("json"))   // "name"

📖 延伸阅读与资源

🎯 实战开发建议

  1. 动手编码 — 只看不练等于没学,每课代码必须自己敲一遍
  2. 使用go docgo doc fmt.Printf 查看标准库文档
  3. 编写测试go test 验证你的理解是否正确
  4. 阅读源码 — 标准库是Go最佳实践的活教材
  5. 项目实战 — 在真实项目中应用所学

⚡ Go性能优化清单

// 1. 预分配切片容量 — 避免频繁扩容
s := make([]int, 0, expectedSize)

// 2. strings.Builder拼接 — 比fmt.Sprintf快3-5倍
var b strings.Builder
b.WriteString("hello")
b.WriteString(" world")
result := b.String()

// 3. sync.Pool对象复用 — 减少GC压力
var bufPool = sync.Pool{
    New: func() interface{} { return new(bytes.Buffer) },
}
buf := bufPool.Get().(*bytes.Buffer)
defer bufPool.Put(buf)

// 4. 减少堆分配 — 小对象栈分配,避免逃逸
// 用 go build -gcflags="-m" 分析逃逸

// 5. 使用benchmark验证性能
func BenchmarkXxx(b *testing.B) {
    for i := 0; i < b.N; i++ {
        // 被测代码
    }
}
// go test -bench=. -benchmem

🔍 调试与排查技巧

// 1. 格式化调试输出
fmt.Printf("%+v
", myStruct)  // 带字段名
fmt.Printf("%#v
", myValue)   // Go语法表示

// 2. log包运行时日志
log.Printf("[DEBUG] value=%v", val)
log.SetFlags(log.LstdFlags | log.Lshortfile)

// 3. delve源码调试器
// 安装: go install github.com/go-delve/delve/cmd/dlv@latest
// 使用: dlv debug ./main.go
// 命令: break main.main / continue / next / print

// 4. pprof性能分析
import _ "net/http/pprof"
go http.ListenAndServe(":6060", nil)
// 访问: http://localhost:6060/debug/pprof/
// 命令: go tool pprof http://localhost:6060/debug/pprof/profile

// 5. race detector竞态检测
// go run -race main.go
// go test -race ./...

📊 Go工具生态

工具用途安装
golangci-lint代码静态检查go install github.com/golangci/golangci-lint/cmd/...@latest
gofumpt代码格式化(增强)go install mvdan.cc/gofumpt@latest
goimports自动管理importgo install golang.org/x/tools/cmd/goimports@latest
dlv源码调试器go install github.com/go-delve/delve/cmd/dlv@latest
air热重载开发go install github.com/cosmtrek/air@latest
swagSwagger文档生成go install github.com/swaggo/swag/cmd/swag@latest
migrate数据库迁移go install -tags 'postgres' github.com/golang-migrate/migrate/v4/cmd/migrate@latest

🏗️ Go项目结构最佳实践

myproject/
├── cmd/                    # 可执行程序入口
│   └── server/
│       └── main.go
├── internal/               # 私有代码(不可外部导入)
│   ├── handler/            # HTTP处理
│   ├── service/            # 业务逻辑
│   ├── repository/         # 数据访问
│   └── model/              # 数据模型
├── pkg/                    # 可复用公共包
│   └── utils/
├── api/                    # API定义(proto/openapi)
├── configs/                # 配置文件
├── scripts/                # 构建/部署脚本
├── test/                   # 集成测试
├── go.mod
├── go.sum
├── Makefile
└── Dockerfile

🌐 Go Web开发生态

类别推荐方案替代方案
Web框架GinEcho / Chi / Fiber
ORMGORMEnt / sqlx / sqlc
配置Viperkoanf
日志zapzerolog / slog
验证validatorgo-playground/validator
缓存go-redisredigo
JWTgolang-jwt
Swaggerswag
测试testify
Mockgomocktestify/mock

💡 编码规范

// 命名规范
// 包名: 小写单词, 不用下划线  package httputil
// 导出: 大写开头              func CreateUser()
// 未导出: 小写开头            func validateInput()
// 接口: -er后缀              type Reader interface{}
// 常量: 驼峰                 const maxRetries = 3
// 枚举: 类型+常量            type Role int; const Admin Role = 0

// 错误处理规范
// 错误变量: Err前缀           var ErrNotFound = errors.New("...")
// 错误类型: Error后缀         type ValidationError struct{...}
// 包装: %w                    fmt.Errorf("查询失败: %w", err)

// 注释规范
// 导出符号必须有注释
// 注释以符号名开头            // CreateUser creates a new user.
// 包注释: doc.go              // Package user handles user operations.