结构体与接口
结构体字面量
go
type User struct {
Name string
Age int
}
u := User{Name: "a", Age: 1}
v := User{"b", 2} // 须按字段声明顺序且不能跳过前面字段混用两种风格
嵌入(匿名字段)将字段与方法提升到外层:
go
type Inner struct{ X int }
type Outer struct {
Inner // 嵌入,不是字段名 Inner
}
var o Outer
o.X = 1 // 提升到 Outer
嵌入指针时,nil 嵌入指针上访问提升字段会 panic。
导出规则
标识符首字母大写:包外可见;小写:包内私有。结构体字段、接口方法名均适用。
接口定义
接口是方法签名的集合。某类型 T 若拥有接口 I 所需的全部方法(且签名一致),则 T 满足 I,无需显式 implements。
空接口 interface{} / any 可被任意具体类型赋值(再取出时常需类型断言)。
接口值的表示
运行时接口值大致为 (动态类型, 动态值)。动态值为 nil 但动态类型非 nil 时,== nil 为 false(常见陷阱):
go
var p *int = nil
var i any = p
// i == nil 为 false,因为接口内动态类型为 *int
类型断言
go
v, ok := i.(ConcreteType) // ok 为 false 时不 panic
v := i.(ConcreteType) // 失败则 panic
switch i.(type) / switch t := i.(type) 做类型分支。
接口设计建议
- 接口越小越好(如
io.Reader单方法),便于测试与组合。 - 在消费者侧定义小接口,而非在生产大包类型处声明巨大接口。
- 需要可空行为时,用具体指针类型或显式
Optional模式,勿依赖「nil 接口值」与「非 nil 接口装 nil 指针」混淆。
comparable 与接口
用作 map 键、== 的类型须可比较。接口动态值比较失败或不可比较类型会 panic。