结构体
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))
}