结构体
1108字约4分钟
2025-02-03
结构体
Go 的结构体(struct) 是带类型的字段(fields)集合。 这在组织数据时非常有用。
示例一
package main
import "fmt"
// 定义一个结构体
type Rect struct {
    width  float64
    height float64
}
// 定义一个方法,计算矩形的面积
func (r Rect) Area() float64 {
    return r.width * r.height
}
// 定义一个方法,计算矩形的周长
func (r Rect) Perimeter() float64 {
    return 2 * (r.width + r.height)
}
func main() {
    // 创建一个矩形对象
    rect := Rect{width: 5.0, height: 3.0}
    // 调用结构体的方法
    area := rect.Area()
    perimeter := rect.Perimeter()
    // 打印计算结果
    fmt.Println("矩形的面积:", area)
    fmt.Println("矩形的周长:", perimeter)
}示例二
package main
import "fmt"
type mystruct struct {
    name    string
    address string
    bothday string
    sex     string
}
// 打印struct信息
func (m *mystruct) showInfo() {
    fmt.Println(
        "name:", m.name,
        "\naddress:", m.address,
        "\nbothday:", m.bothday,
        "\nsex:", m.sex,
    )
}
// 定义走路方法
// 接收者类型为*mystruct,表示该方法是针对mystruct结构体指针的。
func (m *mystruct) walk() {
    fmt.Printf("%s is walking\n", m.name)
}
// 定义吃饭方法
// 接收者类型为mystruct,表示该方法是针对mystruct结构体值的。
func (m mystruct) eat() {
    fmt.Printf("%s is eating\n", m.name)
}
/*
使用场景:
当需要在方法内部修改接收者的属性时,应该使用指针类型的接收者。
当不需要在方法内部修改接收者的属性,并且希望在方法内部复制接收者时,可以使用值类型的接收者。
一般来说,推荐在方法内部修改接收者的属性时使用指针类型的接收者,这样可以避免对接收者值的复制,提高性能并确保方法对结构体的修改能够直接影响到原始对象。
*/
func (m *mystruct) modifyName() {
    m.name = "cn" + m.name
}
func main() {
    my := &mystruct{
        name:    "boge",
        address: "china hubei",
        bothday: "1999-01-02",
        sex:     "男",
    }
    // 调用走路方法
    my.showInfo()
    my.walk()
    you := new(mystruct)
    you.name = "张三"
    you.address = "北京"
    you.bothday = "2001-01-01"
    you.sex = "女"
    you.showInfo()
    you.eat()
    you.modifyName()
    you.showInfo()
}示例三
这个示例代码定义了一个基类 Animal 和两个派生类 Dog 和 Cat。在派生类中,覆盖了基类的 Speak 方法以展示多态。在 main 函数中,创建了 Dog 和 Cat 的对象,并通过调用 Speak 方法展示了封装、继承和多态的特性。
package main
import (
    "fmt"
)
// 定义一个接口
type Speaker interface {
    Speak()
}
// 定义一个基类 Animal
type Animal struct {
    name string
    age  int
}
// 基类 Animal 的方法
func (a *Animal) Speak() {
    fmt.Printf("%s 说:我是一只动物,我的年龄是 %d 岁。\n", a.name, a.age)
}
// 定义一个派生类 Dog,继承自 Animal
type Dog struct {
    *Animal // 嵌入 Animal 类型
    breed   string
}
// 派生类 Dog 的方法,覆盖基类的 Speak 方法
func (d *Dog) Speak() {
    fmt.Printf("%s 说:汪汪汪!我是一只%s,我的年龄是 %d 岁。\n", d.name, d.breed, d.age)
}
// 定义一个派生类 Cat,继承自 Animal
type Cat struct {
    *Animal // 嵌入 Animal 类型
    color   string
}
// 派生类 Cat 的方法,覆盖基类的 Speak 方法
func (c *Cat) Speak() {
    fmt.Printf("%s 说:喵喵喵!我是一只%s猫,我的年龄是 %d 岁。\n", c.name, c.color, c.age)
}
func main() {
    // 创建一个 Dog 对象
    dog := &Dog{
        Animal: &Animal{name: "旺财", age: 3},
        breed:  "拉布拉多",
    }
    // 调用 Speak 方法
    dog.Speak()
    // 创建一个 Cat 对象
    cat := &Cat{
        Animal: &Animal{name: "咪咪", age: 2},
        color:  "橘色",
    }
    // 调用 Speak 方法
    cat.Speak()
    // 使用接口实现多态
    animals := []Speaker{dog.Animal, cat.Animal}
    for _, animal := range animals {
        animal.Speak()
    }
}结构体指针
之前我们了解了值传递和引用传递,如果我想在函数里面或者方法里面修改结构体里面的属性
只能使用结构体指针或者指针方法
package main
import "fmt"
type Student struct {
  Name string
  Age  int
}
func SetAge(info Student, age int) {
  info.Age = age
}
func SetAge1(info *Student, age int) {
  info.Age = age
}
func main() {
  s := Student{
    Name: "阿哲",
    Age:  27,
  }
  fmt.Println(s.Age)
  SetAge(s, 18)
  fmt.Println(s.Age)
  SetAge1(&s, 17)
  fmt.Println(s.Age)
}结构体tag
package main
import (
  "encoding/json"
  "fmt"
)
type Student struct {
  Name string `json:"name"`
  Age  int    `json:"age"`
}
func main() {
  s := Student{
    Name: "阿哲",
    Age:  27,
  }
  byteData, _ := json.Marshal(s)
  fmt.Println(string(byteData))
}这个不写json标签转换为json的话,字段名就是属性的名字
如果再转json的时候,我不希望某个字段被转出来,我可以写一个 -
package main
import (
  "encoding/json"
  "fmt"
)
type Student struct {
  Name     string `json:"name"`
  Age      int    `json:"age"`
  Password string `json:"-"`
}
func main() {
  s := Student{
    Name:     "阿哲",
    Age:      27,
    Password: "123456",
  }
  byteData, _ := json.Marshal(s)
  fmt.Println(string(byteData)) 
}omitempty 空值省略
package main
import (
  "encoding/json"
  "fmt"
)
type Student struct {
  Name string `json:"name"`
  Age  int    `json:"age,omitempty"`
}
func main() {
  s := Student{
    Name: "阿哲",
    Age:  0, // 空值会被省略
  }
  byteData, _ := json.Marshal(s)
  fmt.Println(string(byteData)) 
}