赞
踩
基本介绍
结构体定义方式
Go中结构体定义的基本语法如下:
使用案例如下:
// 定义结构体
type Student struct {
Name string
Age int
Gender string
}
结构体是值类型,不同结构体变量的字段是独立的,互不影响。如下:
说明一下:
创建结构体变量
方式一: 指明结构体的类型,结构体字段采用对应的默认值。
var stu1 Student
fmt.Printf("stu1 = %v\n", stu1) // stu1 = { 0 }
fmt.Printf("stu1 type = %T\n", stu1) // stu1 type = main.Student
方式二: 指明结构体的类型,并初始化结构体字段。
var stu2 = Student{"Alice", 12, "女"}
fmt.Printf("stu2 = %v\n", stu2) // stu2 = {Alice 12 女}
fmt.Printf("stu2 type = %T\n", stu2) // stu2 type = main.Student
方式三: 指明结构体的类型,并通过字段名的方式初始化结构体字段。
var stu3 = Student{
Name: "Alice",
Age: 12,
Gender: "女",
}
fmt.Printf("stu3 = %v\n", stu3) // stu3 = {Alice 12 女}
fmt.Printf("stu3 type = %T\n", stu3) // stu3 type = main.Student
方式四: 通过new函数创建指定类型的结构体变量,得到指向结构体变量的指针。
var stu4 = new(Student)
fmt.Printf("stu4 = %v\n", stu4) // stu4 = &{ 0 }
fmt.Printf("stu4 type = %T\n", stu4) // stu4 type = *main.Student
方式五: 指明结构体的类型,并初始化结构体字段,得到指向结构体变量的指针。
var stu5 = &Student{"Alice", 12, "女"}
fmt.Printf("stu5 = %v\n", stu5) // stu5 = &{Alice 12 女}
fmt.Printf("stu5 type = %T\n", stu5) // stu5 type = *main.Student
方式六: 指明结构体的类型,并通过字段名的方式初始化结构体字段,得到指向结构体变量的指针。
var stu6 = &Student{
Name: "Alice",
Age: 12,
Gender: "女",
}
fmt.Printf("stu6 = %v\n", stu6) // stu6 = &{Alice 12 女}
fmt.Printf("stu6 type = %T\n", stu6) // stu6 type = *main.Student
说明一下:
结构体内存对齐规则
Go中结构体的大小遵循结构体的对齐规则:
其中,不同类型字段的对齐数可能不同,通过unsafe包中的Alignof函数可以获取指定类型对应的对齐数。
结构体大小计算案例
下面代码中分别获取了Student结构体中各个字段的对齐数和大小。如下:
package main import ( "fmt" "unsafe" ) type Student struct { Name string Age uint8 Gender string } func main() { var stu = Student{"Alice", 12, "女"} fmt.Printf("Name align number = %d\n", unsafe.Alignof(stu.Name)) // Name align number = 8 fmt.Printf("Name size = %d\n", unsafe.Sizeof(stu.Name)) // Name size = 16 fmt.Printf("Age align number = %d\n", unsafe.Alignof(stu.Age)) // Age align number = 8 fmt.Printf("Age size = %d\n", unsafe.Sizeof(stu.Age)) // Age size = 1 fmt.Printf("Gender align number = %d\n", unsafe.Alignof(stu.Gender)) // Gender align number = 8 fmt.Printf("Gender size = %d\n", unsafe.Sizeof(stu.Gender)) // Gender size = 16 fmt.Printf("stu align number = %d\n", unsafe.Alignof(stu)) // stu align number = 8 fmt.Printf("stu size = %d\n", unsafe.Sizeof(stu)) // stu size = 40 }
上述结构体变量在内存中的布局如下:
说明一下:
结构体类型转换
Go中的结构体类型是自定义类型,自定义类型之间可以进行类型转换,但要求这两个自定义类型拥有完全相同的字段名、字段个数和字段类型,并且字段的声明顺序也必须相同。如下:
package main import "fmt" type Student struct { Name string Age int Gender string } type Person struct { Name string Age int Gender string } func main() { var per = Person{"Alice", 12, "女"} var stu Student = Student(per) // 类型转换 fmt.Printf("stu = %v\n", stu) // stu = {Alice 12 女} }
Go中可以通过type给自定义类型取别名,但编译器会认为这是一个新的数据类型,在相互赋值时需要进行类型转换,无法直接赋值。如下:
package main import "fmt" type Student struct { Name string Age int Gender string } type Stu Student func main() { var student = Student{"Alice", 12, "女"} var stu Stu = Stu(student) // 类型转换 fmt.Printf("stu = %v\n", stu) // stu = {Alice 12 女} }
字段的Tag标签
在定义结构体时,可以在每个结构体字段的后面设置tag标签,并用反引号将其包裹起来。tag标签可以用于存储与字段相关的信息,例如数据库列名、JSON序列化配置、表单验证等。如下:
package main import ( "encoding/json" "fmt" ) type Student struct { Name string `json:"name"` Age int `json:"age"` Gender string `json:"gender"` } func main() { // json序列化 var stu1 = Student{"Alice", 12, "女"} data, err := json.Marshal(stu1) if err != nil { fmt.Printf("json serialize error, err = %v\n", err) return } fmt.Printf("json string = %v\n", string(data)) // json string = {"name":"Alice","age":12,"gender":"女"} // json反序列 var stu2 Student fmt.Printf("stu2 = %v\n", stu2) // stu2 = { 0 } err = json.Unmarshal(data, &stu2) if err != nil { fmt.Printf("json unserialize error, err = %v\n", err) return } fmt.Printf("stu2 = %v\n", stu2) // stu2 = {Alice 12 女} }
说明一下:
key:"value"
,其中key表示标签的名称,value表示与该标签相关的值,多个标签可以用空格分隔,通过Go中的反射机制可以获取标签的信息。[]byte
类型的,Unmarshal函数在进行JSON反序列化时,要求传入的JSON字符串也是[]byte
类型的,在使用时注意进行类型转换。基本介绍
方法的定义和调用
Go中方法定义的基本语法如下:
创建类型的实例后,通过实例.方法名
的方式即可调用对应的方法。如下:
package main import "fmt" type Student struct { Name string Age int Gender string } func (stu Student) PrintAge() { fmt.Printf("age = %d\n", stu.Age) } func (stu *Student) AgeAdd() { stu.Age++ } func main() { var stu = Student{"Alice", 12, "女"} stu.AgeAdd() stu.PrintAge() // Alice age = 13 }
说明一下:
stu.Age++
等价于(*stu).Age++
。方法调用的传参机制
在Go中,不仅可以通过实例来调用其绑定的方法,通过实例的指针同样能够完成方法的调用。如下:
package main import "fmt" type Student struct { Name string Age int Gender string } func (stu Student) PrintAge() { fmt.Printf("%s age = %d\n", stu.Name, stu.Age) } func (stu *Student) AgeAdd() { stu.Age++ } func main() { // 结构体变量调用方法 var stu1 = Student{"Alice", 12, "女"} stu1.AgeAdd() stu1.PrintAge() // Alice age = 13 // 结构体指针调用方法 var stu2 = &Student{"Bob", 14, "男"} stu2.AgeAdd() stu2.PrintAge() // Bob age = 15 }
说明一下:
String方法
在Go中,如果一个类型实现了String方法,那么在使用fmt包中的函数打印该类型变量时,就会输出String方法返回的字符串。如下:
package main import "fmt" type Student struct { Name string Age int Gender string } func (stu Student) String() string { return fmt.Sprintf("%s是一个%d岁的%s孩\n", stu.Name, stu.Age, stu.Gender) } func main() { var stu = Student{"Alice", 12, "女"} fmt.Printf("stu = %v\n", stu) // stu = Alice是一个12岁的女孩 }
说明一下:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。