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
}