package main
import (
"fmt"
"reflect"
)
/*
type :关键字之定义中新类型
struct : 结构体
结构体并非创建面向对象代码的方式,而是一种数据结构创造方式,旨在满足数据建模需求
允许:结构体套结构体,满足更复杂的数据结构
比较: 结构体比较 运算符 == ,是否相等 !=, 比较结构体首先比较他们类型和值是否相同,对结构体中的每个字段值和类型都会比较。
查询结构体是否相同,reflect.TypeOf()
理解公用、私有值,结构体中首字母大写可以导出,要导出结构体及其字段,结构体及其字段的名称都必须是以大写字母大头!!!
重点:这里的公有和私有,其实就是面向对象中变量继承时的 公有属性和私有属性的意思。建议,目前所有结构体都首字母都大写。
1.使用new 来实例化结构体; m : = new(Movie) //Movie 是一个结构体
2.区分指针引用和值引用,使用结构体是,明确指针引用和值引用的区别很重要。
值引用赋值 比如 a:=b{name:"liu"} ,这样修改a.name="ls",不会影响到b.name,值引用是复制结构体,开辟一块新的内存空间
a只是b的一个副本,而不是指向b的引用。
指针引用赋值 比如 a:=&b{name:"liu"} ,这样修改a.name="ls",会影响到b.name,指针引用是指向结构体内存地址的引用,同一块内存空间
总结。值引用不会互相影响两个变量值的独立,指针引用则会互相影响,因为他们都指向同一块内存地址
总结:值引用只是复制的一个副本,不是指向内存地址的引用;
指针引用,指针是指向内存地址的引用,因此使用它操作的不是结构体的副本而是本身。
指针引用的时候,比如 b:=&a,此时b是指针,因此必须使用*b对其进行引用(打印值)
如果需要修改原始结构体实例,必须使用指针。
如果操作一个结构体,但不想修改原始结构体实例,就使用值。
(指针是go语言中的一种类型,指向变量所在的内存单元,指向内存地址的引用,获得指针的方法,在变量名前加&)
*/
type Students struct {
name string
age int
desc string
address Address
}
type Address struct {
Number int
City string
Street string
}
type Alarm struct {
Time string
Sound string
}
func main() {
a:=Alarm{
Time: "8:00",
Sound: "shanghai",
}
//b:=a //这种b的值改变不了a
b:=&a //这种b的值能改变a的
b.Sound = "beijing"
fmt.Printf("%+v\n",b) //没有改变a的值,内存地址不相同
fmt.Printf("%+v\n",a)
fmt.Printf("%p\n",&a)
fmt.Printf("%p\n",&b)
//ttest();
//NewAlarm("07:00")
}
//嵌套结构体,在声明结构体的时候,嵌套
func ttest(){
var a Students
a.name = "liu"
a.age = 11
a.desc = "上海复旦"
a.address.City="上海"
a.address.Number=0712
a.address.Street="重装路"
kk:=new(Students)
kk.name = "zao"
kk.age =21
cc:=Students{
name:"li",
age:12,
desc:"我是小美丽",
}
fmt.Println(a)
fmt.Println(kk)
fmt.Println(cc)
fmt.Printf("%v,%v岁了\n",a.name,a.age)
}
//结构体的比较用==,会对结构体的类型以及,结构体中每个字段值都做比较,最终全部相同为true,不然为flase
func NewAlarm(time string)Alarm{
a:=Alarm{
Time: time,
Sound: "Klaxon",
}
b:=Alarm{
Time: time,
Sound: "Klaxon",
}
fmt.Println(a)
fmt.Println(b)
fmt.Println(reflect.TypeOf(a))
fmt.Println(reflect.TypeOf(b))
if a==b{
fmt.Println("1111")
}else{
fmt.Println("2222")
}
return a