第四章:结构体与方法

作者:Administrator 发布时间: 2026-03-13 阅读量:1 评论数:0

第四章:结构体与方法

4.1 结构体定义

基本结构体

package main
​
import "fmt"
​
type Person struct {
    Name   string
    Age    int
    Email  string
}
​
type Point struct {
    X, Y float64
}
​
func main() {
    // 方式1:按字段顺序初始化
    p1 := Person{"张三", 25, "zhangsan@example.com"}
    
    // 方式2:指定字段名(推荐)
    p2 := Person{
        Name: "李四",
        Age:  30,
        Email: "lisi@example.com",
    }
    
    // 方式3:部分初始化
    p3 := Person{Name: "王五"}
    
    // 方式4:new创建(返回指针)
    p4 := new(Person)
    p4.Name = "赵六"
    p4.Age = 35
    
    // 方式5:&取地址
    p5 := &Person{Name: "钱七", Age: 40}
    
    fmt.Println(p1)
    fmt.Println(p2)
    fmt.Println(p3)
    fmt.Println(p4)
    fmt.Println(p5)
}

结构体嵌套

package main
​
import "fmt"
​
type Address struct {
    City    string
    Street  string
    ZipCode string
}
​
type Employee struct {
    ID      int
    Name    string
    Address Address  // 嵌套结构体
    Salary  float64
}
​
// 匿名嵌套(提升字段)
type Manager struct {
    Employee    // 匿名嵌套,Employee的字段提升到Manager
    Department string
}
​
func main() {
    emp := Employee{
        ID:   1,
        Name: "张三",
        Address: Address{
            City:    "北京",
            Street:  "长安街",
            ZipCode: "100000",
        },
        Salary: 15000,
    }
    
    // 访问嵌套字段
    fmt.Println(emp.Name)
    fmt.Println(emp.Address.City)
    
    // 匿名嵌套
    mgr := Manager{
        Employee: Employee{
            ID:   2,
            Name: "李四",
        },
        Department: "技术部",
    }
    
    // 可以直接访问Employee的字段
    fmt.Println(mgr.Name)  // 不需要mgr.Employee.Name
    fmt.Println(mgr.Department)
}

4.2 方法

基本方法

package main
​
import (
    "fmt"
    "math"
)
​
type Rectangle struct {
    Width  float64
    Height float64
}
​
// 值接收者方法
func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}
​
// 值接收者方法(不改变原值)
func (r Rectangle) Scale(factor float64) Rectangle {
    return Rectangle{
        Width:  r.Width * factor,
        Height: r.Height * factor,
    }
}
​
// 指针接收者方法(修改原值)
func (r *Rectangle) ScaleInPlace(factor float64) {
    r.Width *= factor
    r.Height *= factor
}
​
// 指针接收者方法(大对象时更高效)
func (r *Rectangle) Perimeter() float64 {
    return 2 * (r.Width + r.Height)
}
​
type Circle struct {
    Radius float64
}
​
func (c Circle) Area() float64 {
    return math.Pi * c.Radius * c.Radius
}
​
func main() {
    rect := Rectangle{Width: 10, Height: 5}
    
    // 调用方法
    fmt.Println("面积:", rect.Area())
    fmt.Println("周长:", rect.Perimeter())
    
    // 值接收者返回新对象
    scaled := rect.Scale(2)
    fmt.Println("原矩形:", rect)
    fmt.Println("缩放后:", scaled)
    
    // 指针接收者修改原对象
    rect.ScaleInPlace(2)
    fmt.Println("原地缩放后:", rect)
}

方法接收者选择

接收者类型

使用场景

值接收者

小对象,不需要修改原值

指针接收者

需要修改原值,或大对象避免拷贝

// 值接收者 - 小对象
type Point struct {
    X, Y float64
}
​
func (p Point) Distance(other Point) float64 {
    dx := p.X - other.X
    dy := p.Y - other.Y
    return math.Sqrt(dx*dx + dy*dy)
}
​
// 指针接收者 - 需要修改
type Counter struct {
    count int
}
​
func (c *Counter) Increment() {
    c.count++
}
​
func (c Counter) Value() int {
    return c.count
}

4.3 结构体标签

package main
​
import (
    "encoding/json"
    "fmt"
    "reflect"
)
​
type User struct {
    ID       int    `json:"id" db:"user_id"`
    Username string `json:"username" db:"user_name"`
    Email    string `json:"email" db:"user_email"`
    Password string `json:"-" db:"user_password"`  // -表示忽略
}
​
func main() {
    user := User{
        ID:       1,
        Username: "张三",
        Email:    "zhangsan@example.com",
        Password: "secret",
    }
    
    // JSON序列化
    data, _ := json.Marshal(user)
    fmt.Println(string(data))
    // 输出: {"id":1,"username":"张三","email":"zhangsan@example.com"}
    // Password被忽略
    
    // 反射读取标签
    t := reflect.TypeOf(user)
    for i := 0; i < t.NumField(); i++ {
        field := t.Field(i)
        fmt.Printf("字段:%s JSON标签:%s DB标签:%s\n",
            field.Name,
            field.Tag.Get("json"),
            field.Tag.Get("db"))
    }
}

4.4 结构体比较

package main
​
import "fmt"
​
type Person struct {
    Name string
    Age  int
}
​
func main() {
    p1 := Person{Name: "张三", Age: 25}
    p2 := Person{Name: "张三", Age: 25}
    p3 := Person{Name: "李四", Age: 30}
    
    // 结构体可以直接比较(如果所有字段都可比较)
    fmt.Println(p1 == p2)  // true
    fmt.Println(p1 == p3)  // false
    
    // 包含不可比较字段的结构体不能比较
    // type Node struct {
    //     Value int
    //     Next  *Node  // 指针可以比较
    // }
}

4.5 项目实战:员工管理系统

package main
​
import "fmt"
​
// 员工结构体
type Employee struct {
    ID       int
    Name     string
    Position string
    Salary   float64
}
​
// 方法:获取员工信息
func (e Employee) GetInfo() string {
    return fmt.Sprintf("ID:%d 姓名:%s 职位:%s 薪资:%.2f",
        e.ID, e.Name, e.Position, e.Salary)
}
​
// 方法:加薪
func (e *Employee) RaiseSalary(percent float64) {
    e.Salary *= (1 + percent/100)
}
​
// 公司结构体
type Company struct {
    Name      string
    Employees []Employee
}
​
// 方法:添加员工
func (c *Company) AddEmployee(e Employee) {
    c.Employees = append(c.Employees, e)
}
​
// 方法:查找员工
func (c Company) FindEmployee(id int) *Employee {
    for i := range c.Employees {
        if c.Employees[i].ID == id {
            return &c.Employees[i]
        }
    }
    return nil
}
​
// 方法:计算总薪资
func (c Company) TotalSalary() float64 {
    total := 0.0
    for _, e := range c.Employees {
        total += e.Salary
    }
    return total
}
​
func main() {
    // 创建公司
    company := Company{Name: "科技有限公司"}
    
    // 添加员工
    company.AddEmployee(Employee{1, "张三", "工程师", 15000})
    company.AddEmployee(Employee{2, "李四", "经理", 25000})
    company.AddEmployee(Employee{3, "王五", "设计师", 12000})
    
    // 显示所有员工
    fmt.Println("=== 员工列表 ===")
    for _, e := range company.Employees {
        fmt.Println(e.GetInfo())
    }
    
    // 查找并加薪
    emp := company.FindEmployee(1)
    if emp != nil {
        fmt.Printf("\n给 %s 加薪10%%\n", emp.Name)
        emp.RaiseSalary(10)
        fmt.Println(emp.GetInfo())
    }
    
    // 显示总薪资
    fmt.Printf("\n公司总薪资: %.2f\n", company.TotalSalary())
}

评论