一、结构体基础
1.1 结构体定义
// 基本结构体定义
type Person struct {
Name string
Age int
Email string
Address Address // 嵌套结构体
}
// 匿名结构体
var user struct {
ID int
Name string
}
1.2 结构体声明与初始化
// 方法1:使用字段名初始化
p1 := Person{
Name: "张三",
Age: 30,
Email: "zhangsan@example.com",
}
// 方法2:按顺序初始化(必须包含所有字段)
p2 := Person{"李四", 25, "lisi@example.com", Address{}}
// 方法3:零值初始化
var p3 Person // 所有字段为零值
// 方法4:使用new
p4 := new(Person) // 返回指针
(*p4).Name = "王五"
p4.Name = "王五" // 简写,Go自动解引用
二、结构体高级特性
2.1 嵌套与匿名嵌套
type Address struct {
City string
Street string
ZipCode string
}
type Company struct {
Name string
Address Address // 具名嵌套
}
type Employee struct {
Name string
Age int
Address // 匿名嵌套(嵌入)
}
func main() {
emp := Employee{
Name: "张三",
Age: 30,
Address: Address{
City: "北京",
Street: "朝阳路",
ZipCode: "100000",
},
}
// 直接访问嵌入字段
fmt.Println(emp.City) // 北京
fmt.Println(emp.Address.City) // 同上
}
import "encoding/json"
type User struct {
ID int `json:"id" db:"user_id"`
Username string `json:"username" db:"username"`
Password string `json:"-"` // 不序列化
Email string `json:"email,omitempty"` // 空值时不序列化
}
func main() {
user := User{
ID: 1,
Username: "alice",
Password: "secret",
}
// JSON 序列化
data, _ := json.Marshal(user)
fmt.Println(string(data)) // {"id":1,"username":"alice"}
}
2.3 结构体方法
type Rectangle struct {
Width float64
Height float64
}
// 值接收者方法(操作副本)
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
// 指针接收者方法(可修改原值)
func (r *Rectangle) Scale(factor float64) {
r.Width *= factor
r.Height *= factor
}
// 方法调用
rect := Rectangle{Width: 10, Height: 5}
area := rect.Area() // 50
rect.Scale(2) // Width=20, Height=10
三、结构体组合与接口
3.1 组合实现"继承"
type Animal struct {
Name string
Age int
}
func (a *Animal) Speak() {
fmt.Println("Animal speaks")
}
type Dog struct {
Animal // 嵌入Animal
Breed string
}
func (d *Dog) Bark() {
fmt.Println("Woof!")
}
func main() {
dog := Dog{
Animal: Animal{Name: "Buddy", Age: 3},
Breed: "Golden Retriever",
}
dog.Speak() // Animal speaks
dog.Bark() // Woof!
fmt.Println(dog.Name) // Buddy
}
3.2 结构体实现接口
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
}
func PrintShapeInfo(s Shape) {
fmt.Printf("面积: %.2f, 周长: %.2f\n", s.Area(), s.Perimeter())
}
四、实用技巧与模式
4.1 工厂函数模式
type Config struct {
host string
port int
timeout time.Duration
}
// 私有字段,使用工厂函数
func NewConfig(host string, port int) *Config {
return &Config{
host: host,
port: port,
timeout: 30 * time.Second, // 默认值
}
}
func (c *Config) WithTimeout(timeout time.Duration) *Config {
c.timeout = timeout
return c
}
4.2 结构体比较
type Point struct {
X, Y int
}
func main() {
p1 := Point{1, 2}
p2 := Point{1, 2}
p3 := Point{2, 3}
fmt.Println(p1 == p2) // true
fmt.Println(p1 == p3) // false
// 包含不可比较字段(如slice)的结构体不能比较
type BadStruct struct {
data []int
}
// b1 == b2 // 编译错误
}
4.3 空结构体
// 零内存占用,用作标记或map的键
type empty struct{}
var signal = struct{}{}
// 用作Set的键
type Set map[string]struct{}
func (s Set) Add(key string) {
s[key] = struct{}{}
}
func (s Set) Contains(key string) bool {
_, ok := s[key]
return ok
}
4.4 内存对齐与优化
// 不良的内存布局
type BadLayout struct {
b bool // 1字节
i int64 // 8字节
s string // 16字节
b2 bool // 1字节
} // 总大小:约32字节(包含填充)
// 优化的内存布局(按大小排序)
type GoodLayout struct {
s string // 16字节
i int64 // 8字节
b bool // 1字节
b2 bool // 1字节
} // 总大小:约24字节
func main() {
fmt.Println(unsafe.Sizeof(BadLayout{})) // 32
fmt.Println(unsafe.Sizeof(GoodLayout{})) // 24
}
六、总结
- 使用工厂函数:提供清晰的对象创建方式
- 小写不可导出字段:通过方法控制访问
- 合理使用指针接收者 :
- 需要修改接收者时
- 结构体较大时避免复制
- 保持一致性(要么全用指针,要么全用值)
- 利用结构体标签:简化序列化/反序列化
- 注意内存布局:对性能敏感的结构体进行字段重排
- 组合优于继承:使用嵌入实现代码复用
- 实现常用接口 :如
Stringer, error 等