接口与反射
接口基础
隐式实现
// Go 的接口是隐式实现的:不需要 implements 关键字
// 只要类型实现了接口定义的所有方法,就自动满足该接口
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
// 组合接口
type ReadWriter interface {
Reader
Writer
}
// File 类型隐式实现了 ReadWriter
type File struct { /* ... */ }
func (f *File) Read(p []byte) (n int, err error) { /* ... */ return }
func (f *File) Write(p []byte) (n int, err error) { /* ... */ return }
// File 自动满足 ReadWriter 接口
var rw ReadWriter = &File{}
接口的内部结构
// interface 底层是一个双字结构
type iface struct {
tab *itab // 类型信息表(类型 + 方法表)
data unsafe.Pointer // 指向具体值
}
// nil interface vs nil value
var r io.Reader // tab=nil, data=nil → r == nil
var r io.Reader = (*bytes.Buffer)(nil) // tab!=nil, data=nil → r != nil !
经典陷阱:接口值不等于 nil,即使底层值为 nil
// ❌ 常见 bug
func getUser() (*User, error) {
var u *User // nil 指针
return u, nil
}
// 调用方
u, err := getUser()
if err != nil {
// 不会进来(err 是 nil)
}
// 更隐蔽的版本
func wrapError(err error) error {
if err == nil {
return nil
}
return fmt.Errorf("wrapped: %w", err)
}
// 这个函数对 nil error 会返回非 nil error!
// 因为 fmt.Errorf 返回的是 *wrapError,它的接口值 (tab, data) 中 data=nil 但 tab!=nil
空接口 interface{}
// Go 1.18+ 之前:interface{} 表示任意类型
// Go 1.18+:any 是 interface{} 的别名
var v any = 42
v = "hello"
v = []int{1, 2, 3}
// type switch 处理
func describe(v any) {
switch v := v.(type) {
case int:
fmt.Printf("int: %d\n", v)
case string:
fmt.Printf("string: %s\n", v)
case []int:
fmt.Printf("[]int: %v\n", v)
default:
fmt.Printf("unknown: %T\n", v)
}
}
接口设计原则
1. 接口越小越好
// ✓ 好:小接口(io.Reader 只有 1 个方法)
type Reader interface {
Read(p []byte) (n int, err error)
}
// ✓ 好:标准库的小接口
type Stringer interface {
String() string
}
type Closer interface {
Close() error
}
type Error interface {
Error() string
}
// ❌ 不好:大接口(违反接口隔离原则)
type UserService interface {
GetByID(id string) (*User, error)
Create(user *User) error
Update(user *User) error
Delete(id string) error
List(page, size int) ([]*User, error)
Search(query string) ([]*User, error)
Export(format string) ([]byte, error)
Import(data []byte) error
SendEmail(id string, subject, body string) error
ResetPassword(id string) error
}
// ✓ 好:按职责拆分
type UserReader interface {
GetByID(id string) (*User, error)
List(page, size int) ([]*User, error)
Search(query string) ([]*User, error)
}
type UserWriter interface {
Create(user *User) error
Update(user *User) error
Delete(id string) error
}
type UserReadWriter interface {
UserReader
UserWriter
}
2. 消费者定义接口
// ✓ 正确:在消费者侧定义接口(只声明需要的方法)
// service/user_service.go
type UserRepository interface {
FindByID(ctx context.Context, id string) (*entity.User, error)
}
type UserService struct {
repo UserRepository // 依赖接口,不依赖具体实现
}
// repository/user_repo.go(不需要知道接口的存在)
type UserRepository struct {
db *gorm.DB
}
func (r *UserRepository) FindByID(ctx context.Context, id string) (*entity.User, error) {
// ...
}
// ❌ 错误:在实现侧定义接口
// repository/user_repo.go
// type UserRepository interface { ... } // 不要在实现包定义接口
3. 常见标准库接口
| 接口 | 包 | 方法 | 用途 |
|---|
io.Reader | io | Read(p []byte) (n int, err error) | 读取数据 |
io.Writer | io | Write(p []byte) (n int, err error) | 写入数据 |
io.Closer | io | Close() error | 关闭资源 |
fmt.Stringer | fmt | String() string | 字符串表示 |
error | builtin | Error() string | 错误 |
sort.Interface | sort | Len(), Less(), Swap() | 排序 |
json.Marshaler | encoding/json | MarshalJSON() ([]byte, error) | 自定义 JSON 序列化 |
json.Unmarshaler | encoding/json | UnmarshalJSON([]byte) error | 自定义 JSON 反序列化 |
driver.Valuer | database/sql | Value() (driver.Value, error) | 自定义 SQL 值 |
sql.Scanner | database/sql | Scan(src interface{}) error | 自定义 SQL 扫描 |
http.Handler | net/http | ServeHTTP(w, r) | HTTP 处理器 |
http.HandlerFunc | net/http | func(http.ResponseWriter, *http.Request) | 函数适配器 |
类型断言与 type switch
// 类型断言
var i interface{} = "hello"
s, ok := i.(string) // s="hello", ok=true
n, ok := i.(int) // n=0, ok=false
// type switch
switch v := i.(type) {
case string:
fmt.Println("string, len:", len(v))
case int:
fmt.Println("int, value:", v)
case fmt.Stringer:
fmt.Println("Stringer:", v.String())
default:
fmt.Printf("unknown type %T\n", v)
}
// 接口到接口的断言
var r io.Reader = strings.NewReader("hello")
rw, ok := r.(io.Writer) // strings.Reader 没实现 Writer,ok=false
反射 reflect
原则:能不用反射就不用。反射代码可读性差、性能低、不安全(运行时才报错)。
reflect.Type vs reflect.Value
import "reflect"
type User struct {
Name string `json:"name" validate:"required"`
Age int `json:"age" validate:"min=0"`
}
u := User{Name: "小徐", Age: 28}
// 获取 Type
t := reflect.TypeOf(u)
fmt.Println(t.Name()) // User
fmt.Println(t.Kind()) // struct
fmt.Println(t.NumField()) // 2
// 获取 Value
v := reflect.ValueOf(u)
fmt.Println(v.Kind()) // struct
// 遍历字段
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
value := v.Field(i)
tag := field.Tag.Get("json")
fmt.Printf("%s %s = %v (json:%s)\n",
field.Name, field.Type, value.Interface(), tag)
}
// 输出:
// Name string = 小徐 (json:name)
// Age int = 28 (json:age)
修改值(需要指针)
u := User{Name: "小徐", Age: 28}
// ❌ 反射值不可寻址
v := reflect.ValueOf(u)
// v.FieldByName("Name").SetString("小王") // panic: not addressable
// ✓ 通过指针修改
v = reflect.ValueOf(&u).Elem() // Elem() 解引用
v.FieldByName("Name").SetString("小王")
v.FieldByName("Age").SetInt(30)
fmt.Println(u) // {小王 30}
动态调用方法
type Calculator struct{}
func (c Calculator) Add(a, b int) int { return a + b }
c := Calculator{}
v := reflect.ValueOf(c)
// 获取方法
method := v.MethodByName("Add")
// 构造参数
args := []reflect.Value{
reflect.ValueOf(3),
reflect.ValueOf(5),
}
// 调用
results := method.Call(args)
fmt.Println(results[0].Int()) // 8
反射性能对比
| 操作 | 直接调用 | 反射调用 | 性能比 |
|---|
| 字段读取 | ~1ns | ~50ns | 50x |
| 字段设置 | ~1ns | ~80ns | 80x |
| 方法调用 | ~2ns | ~200ns | 100x |
反射实际应用
func validateStruct(s interface{}) error {
v := reflect.ValueOf(s)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
t := v.Type()
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
value := v.Field(i)
validateTag := field.Tag.Get("validate")
if validateTag == "" {
continue
}
rules := strings.Split(validateTag, ",")
for _, rule := range rules {
if err := applyRule(field.Name, value, rule); err != nil {
return err
}
}
}
return nil
}
// 2. 通用深拷贝
func DeepCopy(src interface{}) interface{} {
if src == nil {
return nil
}
v := reflect.ValueOf(src)
return deepCopyValue(v).Interface()
}
func deepCopyValue(v reflect.Value) reflect.Value {
switch v.Kind() {
case reflect.Ptr:
if v.IsNil() {
return reflect.Zero(v.Type())
}
copy := reflect.New(v.Elem().Type())
copy.Elem().Set(deepCopyValue(v.Elem()))
return copy
case reflect.Slice:
if v.IsNil() {
return reflect.Zero(v.Type())
}
copy := reflect.MakeSlice(v.Type(), v.Len(), v.Len())
for i := 0; i < v.Len(); i++ {
copy.Index(i).Set(deepCopyValue(v.Index(i)))
}
return copy
case reflect.Map:
if v.IsNil() {
return reflect.Zero(v.Type())
}
copy := reflect.MakeMap(v.Type())
iter := v.MapRange()
for iter.Next() {
copy.SetMapIndex(iter.Key(), deepCopyValue(iter.Value()))
}
return copy
default:
return v
}
}
// 3. 结构体转 map
func StructToMap(s interface{}) map[string]interface{} {
result := make(map[string]interface{})
v := reflect.ValueOf(s)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
t := v.Type()
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
jsonTag := field.Tag.Get("json")
if jsonTag == "" || jsonTag == "-" {
continue
}
// 处理 omitempty 等选项
name := strings.Split(jsonTag, ",")[0]
result[name] = v.Field(i).Interface()
}
return result
}
何时用反射
| 场景 | 是否用反射 | 替代方案 |
|---|
| ORM 映射 | ✓ | 代码生成(codegen) |
| JSON 序列化 | ✓(标准库已实现) | 直接用 encoding/json |
| 配置解析 | ✓(viper 等) | mapstructure |
| 验证器 | ✓ | go-playground/validator |
| 依赖注入 | ✓ | 代码生成(wire) |
| 业务逻辑 | ✗ | 接口 + 类型断言 |
| 性能敏感路径 | ✗ | 直接调用 |
| 简单类型判断 | ✗ | type switch |