结构体是一个自定义的数据类型,是值类型
声明结构体
type 结构体名称 struct {
field_1 type
field_2 type
}
注意事项
字段声明语法同变量,示例:字段名 字段类型
字段的类型可以为:基本类型、数组或引用类型
创建一个结构体变量后,如果没有给字段赋值,都会对应一个默认值,规则如下:
布尔类型默认为false
数值类型默认为0
字符串类型默认为空""
数组类型的默认值与它的元素类型相关,比如:Scores [3]int 默认值为:[0,0,0]
指针、切片(slice)、map默认值都是nil,即还没有分配空间
不同的结构体字段之间是独立的,互不影响,一个字段值的改变不会影响另外一个
基本使用
package main
import "fmt"
type Stu struct {
Name string
Age int
Score float32
Ptr *int // 指针
Array [3]int // 数组
Slice []string // 切片
Map1 map[string]string // map
}
func main() {
// 结构体基本使用
var student Stu
student.Name = "宋江"
student.Age = 20
student.Score = 60
fmt.Println(student)
// 单独访问变量
fmt.Printf("Name:%v,Age:%v,Score:%v\n", student.Name, student.Age, student.Score)
// 给数组赋值
student.Array = [3]int{1, 2, 0}
student.Array[2] = 3
// 给切片赋值,切片赋值必须make!!!
student.Slice = make([]string, 3)
student.Slice[0] = "卢俊义"
student.Slice[1] = "吴用"
student.Slice[2] = "公孙胜"
student.Slice = append(student.Slice, "林超") // 切片超过定义范围,再追加需用append函数
// 给map赋值,map赋值必须make!!!
student.Map1 = make(map[string]string)
student.Map1["no1"] = "吃饭"
student.Map1["no2"] = "睡觉"
student.Map1["no3"] = "打游戏"
fmt.Println(student)
}
不同的结构体字段之间是独立性
package main
import "fmt"
type Stu struct {
Name string
Age int
Score float32
}
func main() {
// 不同的结构体字段之间是独立的,互不影响
var student1 Stu
student1.Name = "宋江"
student1.Age = 20
student1.Score = 60
student2 := student1
student2.Score = 70 // 此处元素值的改变并不会影响student1
fmt.Println(student1)
fmt.Println(student2)
}
创建结构体实例的四种方式
看代码注释,推荐第二种方式
package main
import "fmt"
type Person struct {
Name string
Age int
}
func main() {
// 第一种方式
var person1 Person
person1.Name = "宋江"
person1.Age = 20
fmt.Println(person1)
// 第二种方式
var person2 = Person{
Name: "吴用",
Age: 19,
}
fmt.Println(person2)
// 第三种方式,person3是指针类型
var person3 *Person = new(Person) // *Person可以省略不写
(*person3).Name = "卢俊义" // 可以省略为:person3.Name = "卢俊义",(*person3)等价于person3
(*person3).Age = 21 // 可以省略为:person3.Age = 21,(*person3)等价于person3
fmt.Println(*person3)
// 第四种,person4算指针类型,可以直接赋值,也可以重新赋值
var person4 *Person = &Person{ // *Person可以省略不写
Name: "公孙胜",
Age: 22,
}
person4.Name = "林冲" // 重写赋值,标准写法:(*person4).Name = "林冲",这里使用的是省略方式
person4.Age = 23 // 重写赋值,标准写法:(*person4).Age = 23,这里使用的是省略方式
fmt.Println(*person4)
}
结构体指针的使用
package main
import "fmt"
type Person struct {
Name string
Age int
}
func main() {
var person = Person{
Name: "宋江",
Age: 19,
}
personPtr := &person // 定义一个指针
personPtr.Name = "吴用" // 修改指针的Name,personPtr是省略方式
(*personPtr).Age = 20 // 修改指针的Age,*personPtr是指针标准方式
fmt.Println(person)
fmt.Println(*personPtr)
}
结构体细节
结构体是用户单独定义的类型,和其他类型进行转换时需要有完全相同的字段(字段名、个数、类型)
package main
import "fmt"
type Person struct {
Name string
Age int
}
type Person1 struct {
Name string
Age int
}
func main() {
var person = Person{
Name: "宋江",
Age: 19,
}
// var person1 Person1 = person // 这种直接赋值是不行的,需要做强转
var person1 Person1 = Person1(person) // 强转的前提是两个结构体必须完全一样
fmt.Println(person)
fmt.Println(person1)
}
结构体进行type重新定义(相当于取别名),Golang认为是新的数据类型,但是相互间可以强转
package main
import "fmt"
type integer int // 新定义数据类型integer,相当于int的别名
func main() {
var i integer = 10
var j int
// j = i // 直接赋值是不行,需要强转
j = int(i)
fmt.Println(i, "---", j)
}
struct 的每个字段上,可以写上一个tag,该tag可以通过反射机制获取,常见的使用场景是json的序列化和反序列化
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
Name string `json:"name"` // tag的作用是返回json后Name转换为name(首字母小写)
Age int `json:"age"`
As string `json:"as"`
}
func main() {
var persons = map[int]Person{
0: {
Name: "宋江",
Age: 19,
As: "及时雨",
},
1: {
Name: "吴用",
Age: 20,
As: "神机军师",
},
}
var personStr, err = json.Marshal(persons)
if err != nil {
fmt.Println("json转码错误", err)
} else {
fmt.Println(string(personStr))
}
}
返回:{"0":{"name":"宋江","age":19,"as":"及时雨"},"1":{"name":"吴用","age":20,"as":"神机军师"}}