结构体(struct),是由一系列具有相同类型或不同类型的数据构成的数据集合,也叫结构。 (可以理解为其他编程语言中的类)
- 结构体既可以定义在函数内,也可以定义在函数外,函数外为全局结构体可以跨包访问(前提是结构体首字母大写)
- 结构体变量是值类型,可以使用fmt.Printf("%p", &结构体变量)来查看其内存地址;由于结构体是值类型,在方法传递时,希望传递的是结构体地址,这时就可以使用结构体指针来完成,可以结合new(T)函数创建结构体指针;
- 双等于号比较时候,看两侧是什么类型,如果是值类型,就看内容是否相同,即使地址不同,也为true,如果两侧是指针类型,就会比较内存地址是否相同;
package main
import (
"fmt"
)
// 声明结构体,可以理解为创建一个类
type People struct { // 结构体名称首字母大写,能被其他包访问,小写无法被其他包访问(包括其属性也无法被访问);
Name string // 属性1 如果结构体能被访问,这里的大写就能被其他包访问,小写无法被其他包访问;可以理解为有2道门;
age int // 属性2
}
func main() {
// 声明结构体变量
// 只声明不赋值
var p1 People
fmt.Println(p1) // { 0} 初始值为对应类型的默认值; string类型默认值为空字符串;int类型默认为0;
// 声明的同时赋值, 位置参数
p2 := People{"张三", 24}
fmt.Println(p2) // {张三 24}
// 声明的同时赋值, 关键字参数
p3 := People{age: 22, Name: "李四"}
fmt.Println(p3) // {李四 22}
// 获取结构体变量对应的值:
fmt.Println(p1.Name, p1.age) // 0
fmt.Println(p2.Name, p2.age) // 张三 24
fmt.Println(p3.Name, p3.age) // 李四 22
//在结构体中,用"=="判断的是结构体中的内容是否相同,如果地址不同,但是内容相同,返回值就为true
// 再声明一个结构体变量p4, 明显这个结构体变量与p2不同,如果给p4赋值和p2一样
var p4 People
p4.age = 24
p4.Name = "张三"
// 利用双等于号"=="来判断
fmt.Printf("p2: %p, p4: %p \n", &p2, &p4) // p2: 0xc0000044e0, p4: 0xc000004540
fmt.Println("p2==p4? ", p2 == p4) // p2==p4? true
// 结构体指针
p5 := new(People) // 结构体是值类型,所以创建结构体指针时已经开辟了内存空间
fmt.Println(p5) // &{ 0}
fmt.Println(p5 == nil) // false
// 由于结构体中的值不是指针类型,所以可以直接调用
p5.Name = "王五"
fmt.Println(p5) // &{王五 0}
// 由于p5是使用new()函数创建出来的,所以p5是指针
p6 := p5
fmt.Println(p5, p6) // &{王五 0} &{王五 0}
fmt.Printf("p5: %p, p6: %p \n", p5, p6) // p5: 0xc000096500, p6: 0xc000096500 引用类型不用&取地址
// 从上面的地址可以看到,p5和p6指向的是同一个内存地址,所以,修改其中一个,就会影响另外一个
p5.age = 23
p6.Name = "赵六"
fmt.Println(p5, p6) // &{赵六 23} &{赵六 23}
// 双等于号比较时候,看两侧是什么类型,如果是值类型,就看内容是否相同,即使地址不同,也为true,如果两侧是指针类型,就会比较内存地址是否相同;
p7 := &People{"A", 23}
p8 := &People{"A", 23}
fmt.Printf("p7: %T, p8: %T \n", p7, p8) // p7: *main.People, p8: *main.People
fmt.Printf("p7: %p, p8: %p \n", p7, p8) // p7: 0xc000004640, p8: 0xc000004660
fmt.Println("p7 == p8 ?", p7 == p8) // p7 == p8 ? false
// 值类型与指针类型比较时的转换: *指针类型, &值类型
p9 := People{"A", 23}
fmt.Println("p8==&p9?", p8==&p9) // p8==p9? false 使用&p9取到p9的地址,这时候两边都是指针类型,需要判断内存地址是否相同
fmt.Println("*p8==p9?", *p8==p9) // p8==p9? true 使用*p8取到指针p8里面的值,这时候两边都是值类型,只需判断内容是否相同
}