GO学习笔记(5)
五. 结构体
5.1. 结构体定义和初始化
func structDefine() { // 关键字: type // 1.自定义类型, 具有int相同的特性, 但类型是自定义类型: main.myInt, 表示main包下的myInt类型 type myInt int var a myInt fmt.Printf("%T \n", a) // main.myInt // 2. 类型别名, 本质上就是int类型 type aint = int var b aint fmt.Printf("%T \n", b) // int // 3. 结构体, 用 . 访问成员 // 3.1 定义结构体 type Stu struct { name string age int score float32 } // 3.2 实例化 stu1 := Stu{ name: "马大哈", age: 12, score: 10.5, } fmt.Printf("%v\n", stu1) // {马大哈 12 10.5} fmt.Printf("%#v\n", stu1) // main.Stu{name:"马大哈", age:12, score:10.5} // 3.3 匿名结构体 var stu2 struct { name string age int } stu2.name = "李二狗" stu2.age = 55 fmt.Printf("%v\n", stu2) // {李二狗 55} fmt.Printf("%#v\n", stu2) // struct { name string; age int }{name:"李二狗", age:55} // 3.4 结构体指针, 用new实例化 p1 := new(Stu) fmt.Printf("%T \n", p1) // *main.Stu fmt.Printf("%#v\n", p1) // &main.Stu{name:"", age:0, score:0} p1.name = "丽丽" p1.age = 18 p1.score = 99 fmt.Printf("%#v\n", p1) // &main.Stu{name:"丽丽", age:18, score:99} // 3.5 取结构体的地址实例化 p2 := &Stu{} fmt.Printf("%T \n", p2) // *main.Stu fmt.Printf("%#v\n", p2) // &main.Stu{name:"", age:0, score:0} // 3.6 结构体初始化 // 3.6.1 声明完成后, 结构体其实已经实例化完成,所有的成员都是默认0值 var p3 Stu fmt.Printf("%#v\n", p3) // main.Stu{name:"", age:0, score:0} // 3.6.2 键值对初始化 p4 := Stu{ name: "二狗子", age: 10, score: 0, } fmt.Printf("%#v\n", p4) // main.Stu{name:"二狗子", age:10, score:0} // 3.6.3 结构体指针初始化 p5 := &Stu{ name: "Go", age: 0, score: 0, } fmt.Printf("%#v\n", p5) // &main.Stu{name:"Go", age:0, score:0} // 3.6.4 值的列表初始化 // 注意: 1.必须初始化结构体的所有字段 // 2.初始值的填充顺序必须与字段在结构体中的声明顺序一致 // 3.该方式不能和键值初始化方式混用 p6 := Stu{ "谁呀", 18, 20, } fmt.Printf("%#v\n", p6) // main.Stu{name:"谁呀", age:18, score:20} }
5.2. 小坑, 需要注意哈
func notice() {
type student struct {
name string
age int
}
m := make(map[string]*student)
stus := []student{
{name: "张三", age: 18},
{name: "李四", age: 23},
{name: "王五", age: 28},
}
for i, stu := range stus {
fmt.Printf("%v, %p, %p \n",stu, &stu, &stus[i])
m[stu.name] = &stu
}
/** 输出: stu是 元素的拷贝, 并不是元素的引用
{张三 18}, 0xc000096440, 0xc0000d6000
{李四 23}, 0xc000096440, 0xc0000d6018
{王五 28}, 0xc000096440, 0xc0000d6030
*/
for k, v := range m {
fmt.Println(k, ":", v.name)
}
/** 输出:
张三 : 王五
李四 : 王五
王五 : 王五
原因: 因为for range创建的是每个元素的拷贝,而不是直接返回每个元素的引用
在for _, stu := range stus的时候,返回的stu其实并不是stus元素的引用,而是新的变量
*/
}
5.3. 方法和接收者
// 方法和接收者 // 1. 接收者的类型可以是任何类型 // 2. 不能给别的包的类型定义方法 type Animal struct { name string age int } // 接收者: 方法就只属于Animal这个类型,其他类型无法调用 func (a Animal) info() { fmt.Println(a.name, a.age) } // 修改成员的时候, 接收者类型必须是引用类型 func (a *Animal) setAge(age int) { a.age = age } func (a Animal) setAge1(age int) { a.age = age } type myInt int func (m myInt) printInfo() { fmt.Println("我是", m) } // 以下这些情况,接收者类型应该使用引用类型: // 1.需要修改接收者中的值 // 2.接收者是拷贝代价比较大的大对象 // 3.保证一致性,如果有某个方法使用了指针接收者,那么其他的方法也应该使用指针接收者。 func method() { a := Animal{ name: "阿猫", age: 1, } a.info() // 阿猫 1 a.setAge(20) a.info() // 阿猫 20 a.setAge1(18) a.info() // // 阿猫 20 // 为自定义类型定义了方法 var b myInt = 10 b.printInfo() // 我是 10 }
5.4. JSON序列化
func json2struct() {
// 只要是可导出成员(变量首字母大写), 都可以转成json
type Employee struct {
Name string
Salary float32
seniority int
}
a := &Employee{
Name:"渣渣灰",
Salary:12.8,
seniority:2,
}
data, _ := json.Marshal(a)
fmt.Printf("%s\n",data) // {"Name":"渣渣灰","Salary":12.8}
// 反序列, 变量为私有(首字母小写), 无法被识别
s := `{"Name":"渣渣渣","Salary":12.5, "seniority":3}`
c := &Employee{}
json.Unmarshal([]byte(s), c)
fmt.Printf("%#v\n", c) // &main.Employee{Name:"渣渣渣", Salary:12.5, seniority:0}
}
5.5. 结构体标签
func tag() { // 结构体标签: Tag在结构体字段的后方定义, 由一对反引号包裹起来, 键与值使用冒号分隔,值用双引号括起来 type Employee struct { Name string `json:"name"` Salary float32 seniority int } a := &Employee{ Name: "渣渣灰", Salary: 12.8, seniority: 2, } data, _ := json.Marshal(a) // 有标签的成员,在json中的字段名为标签的值 fmt.Printf("%s\n", data) // {"name":"渣渣灰","Salary":12.8} // 反序列的时候, 有标签的成员可以识别标签值, 也可以识别成员本身的名字 s1 := `{"Name":"渣渣","Salary":1.5, "seniority":1}` s2 := `{"name":"渣渣渣","Salary":12.5, "seniority":3}` c1 := &Employee{} c2 := &Employee{} json.Unmarshal([]byte(s1), c1) json.Unmarshal([]byte(s2), c2) fmt.Printf("%#v\n", c1) // &main.Employee{Name:"渣渣", Salary:1.5, seniority:0} fmt.Printf("%#v\n", c2) // &main.Employee{Name:"渣渣渣", Salary:12.5, seniority:0} }