jee said

Go语言结构体与方法

unclejee & AI
910 words
5min read
Go语言结构体与方法

Go语言结构体与方法

Go语言通过结构体和方法来实现面向对象编程的特性。与传统的类不同,Go的结构体和方法是分离的,这使得代码更加灵活。

结构体定义

基本语法

type Person struct {
    Name string
    Age  int
}

type Point struct {
    X, Y float64
}

结构体实例化

// 方式1:按顺序初始化
p1 := Person{"张三", 30}

// 方式2:按字段名初始化(推荐)
p2 := Person{
    Name: "李四",
    Age:  25,
}

// 方式3:使用new函数
p3 := new(Person)
p3.Name = "王五"
p3.Age = 35

结构体标签

type User struct {
    ID       int    `json:"id"`
    Username string `json:"username" db:"user_name"`
    Email    string `json:"email" db:"email"`
    Created  time.Time `json:"created_at"`
}

方法定义

Go语言的方法是带有接收者的函数。

值接收者

type Rectangle struct {
    Width  float64
    Height float64
}

// 值接收者
func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

func main() {
    rect := Rectangle{Width: 3, Height: 4}
    fmt.Println(rect.Area())  // 12
}

指针接收者

type Counter struct {
    count int
}

// 指针接收者(可以修改原值)
func (c *Counter) Increment() {
    c.count++
}

func (c *Counter) GetCount() int {
    return c.count
}

func main() {
    c := Counter{count: 0}
    c.Increment()
    fmt.Println(c.GetCount())  // 1
}

值接收者 vs 指针接收者

type Point struct {
    X, Y float64
}

// 值接收者:不修改原值
func (p Point) String() string {
    return fmt.Sprintf("(%f, %f)", p.X, p.Y)
}

// 指针接收者:修改原值
func (p *Point) Move(dx, dy float64) {
    p.X += dx
    p.Y += dy
}

结构体组合

Go语言通过组合而非继承来复用代码。

匿名嵌入

type Address struct {
    City    string
    Country string
}

type Person struct {
    Name    string
    Address  // 匿名嵌入
}

func main() {
    p := Person{
        Name: "张三",
        Address: Address{
            City:    "北京",
            Country: "中国",
        },
    }
    // 可以直接访问嵌入字段
    fmt.Println(p.City)      // 北京
    fmt.Println(p.Country)   // 中国
}

方法提升

func (a Address) FullAddress() string {
    return fmt.Sprintf("%s, %s", a.City, a.Country)
}

func main() {
    p := Person{
        Name:    "张三",
        Address: Address{City: "北京", Country: "中国"},
    }
    // 嵌入类型的方法被提升
    fmt.Println(p.FullAddress())  // 北京, 中国
}

命名嵌入

type Person struct {
    Name    string
    Addr Address  // 命名嵌入
}

func main() {
    p := Person{
        Name: "张三",
        Addr: Address{City: "北京", Country: "中国"},
    }
    // 需要通过嵌入字段访问
    fmt.Println(p.Addr.City)  // 北京
}

结构体比较

type Point struct {
    X, Y float64
}

func main() {
    p1 := Point{X: 1, Y: 2}
    p2 := Point{X: 1, Y: 2}
    p3 := Point{X: 1, Y: 3}

    fmt.Println(p1 == p2)  // true
    fmt.Println(p1 == p3)  // false
}

结构体与JSON

序列化

type User struct {
    ID       int    `json:"id"`
    Username string `json:"username"`
    Email    string `json:"email"`
}

func main() {
    user := User{
        ID:       1,
        Username: "zhangsan",
        Email:    "zhangsan@example.com",
    }
    data, _ := json.Marshal(user)
    fmt.Println(string(data))
    // {"id":1,"username":"zhangsan","email":"zhangsan@example.com"}
}

反序列化

func main() {
    jsonData := `{"id":1,"username":"zhangsan","email":"zhangsan@example.com"}`
    var user User
    json.Unmarshal([]byte(jsonData), &user)
    fmt.Printf("%+v\n", user)
    // {ID:1 Username:zhangsan Email:zhangsan@example.com}
}

最佳实践

  1. 使用指针接收者:当方法需要修改结构体时
  2. 使用值接收者:当方法不需要修改结构体时
  3. 使用组合而非继承:通过嵌入实现代码复用
  4. 合理使用结构体标签:JSON、数据库映射等场景
  5. 导出字段:首字母大写的字段才能被外部包访问

总结

Go语言的结构体和方法提供了一种简洁而强大的面向对象编程方式。通过组合而非继承,Go的代码更加灵活和可维护。掌握结构体和方法的用法是Go语言开发的基础。