Golang——结构体创建与初始化、结构体与数组、结构体与切片、结构体与map、结构体作为函数参数、结构体方法、结构体方法继承
結構體:
- 結構體是由一系列具有相同類型或不同類型的數據構成的數據集合
- 結構體可以很好的管理一批有聯系的數據,使用結構體可以提高程序的易讀性,類似于Java的類一樣
- 不能在結構體直接賦值
- 字段名必須唯一,可用_補位,支持使用自身類型的指針成員。字段名、排列順序屬類 型組成部分。除對齊處理外,編譯器不會優化、調整內存布局。
- struct {}是一個無元素的結構體類型,通常在沒有信息存儲時使用。優點是大小為0,不需要內存來存儲struct {}類型的值
- struct {} {}是一個復合字面量,它構造了一個struct {}類型的值,該值也是空
結構體的創建與初始化:
創建格式:
type 結構體名 struct {成員名 數據類型 }順序初始化格式:
var 變量名 結構體名 = 結構體名{成員值1,成員值2}部分初始化格式:
var 變量名 結構體名 = 結構體名{成員名:成員值,成員名:成員值}通過結構體變量.成員方式初始化:
var 變量名 結構體名變量名.成員名 = 成員值演示:
// 結構體可以創建在函數外面,這樣是全局的,如果是定義在函數的里面就是局部的 type Student struct {// 成員名稱不加var關鍵字id intname stringage intaddr string }func structDemo() {// 順序初始化var s1 Student = Student{001, "itzhuzhu", 23, "廣州"}// 部分初始化var s2 Student = Student{name: "itzhuzhu", age: 23}//通過結構體變量.成員方式初始化var stu Studentstu.name = "itzhuzhu"stu.id = 23fmt.Println(s1) //{1 itzhuzhu 2 廣州}fmt.Println(s2) //{0 itzhuzhu 23 }fmt.Println(stu) //{23 itzhuzhu 0 } }僅在字段類型全部支持時,才可做相等操作
func main() {type data struct {x inty map[string]int}d1 := data{x: 100,}d2 := data{x: 100,}println(d1 == d2) // 無效操作: struct containing map[string]int cannot be compared }可使用指針直接操作結構字段,但不能是多級指針
func main() {type user struct {name stringage int}p := &user{name: "Tom",age: 20,}p.age++p2 := &p*p2.name = "Jack" // 報錯: p2.name undefined (type **user has no field or method name) }空結構:
空結構struct{ }是指沒有字段的結構類型。它比較特殊,是因為無論是其自身,還是作為數組元素類型,其長度都為零
func main() {var a struct{}var b [100]struct{}println(unsafe.Sizeof(a), unsafe.Sizeof(b)) }輸出:
0 0盡管沒有分配存儲內存,但依然可以操作數組元素,對應切片len、cap屬性也正常
func main() {var d [100]struct{}s := d[:]d[1] = struct{}{}s[2] = struct{}{}fmt.Println(s[3], len(s), cap(s)) }輸出:
{} 100 100空結構對象可用于channel作為事件通知
func main() {exit := make(chan struct{})go func() {println("hello, world!")exit <- struct{}{}}()<-exitprintln("end.") }匿名字段:
所謂匿名字段(anonymousfield),是指沒有名字,僅有類型的字段。也被稱作嵌入字段或嵌入類型。
type attr struct {perm int } type file struct {name stringattr // 僅有類型名 }從編譯器角度看,這只是隱式以類型標識作名字的字段。相當于語法糖,可實現面向對象 語言中引用基類成員的使用方法
func main() {type attr struct {age int}type file struct {name stringattr}f := file{"itzhuzhu", attr{24}}f = file{name: "itzhuzhu",attr: attr{age: 24,},}f.age = 24 //設置匿名字段成員println(f.age) //讀取匿名字段成員 }對于其他包里的類型,隱式字段名字不包括包名稱
func main() {type data struct {os.File}d := data{File: os.File{}, // 注意區分字段名字和初始化成員對象的差別}fmt.Printf("%#v\n", d) }不僅僅是結構體,除接口指針和多級指針以外的任何命名類型都可作為匿名字段
func main() {type data struct {*int // 嵌入指針類型string}x := 100d := data{int: &x, // 使用基礎類型作為字段名string: "abc",}fmt.Printf("%#v\n", d) }未命名類型沒有名字標識,自然無法提供隱式字段名
type a *int type b **int type c interface{} type d struct {*a // 錯誤: embedded type cannot be a pointerb // 錯誤: embedded type cannot be a pointer*c // 錯誤: embedded type cannot be a pointer to interface }不能將基礎類型和其指針類型同時嵌入,因為兩者字段名字相同
type data struct {*intint // 錯誤: duplicate field int }雖然可以像普通字段那樣訪問匿名字段成員,但會存在重名問題。默認情況下,編譯器從 當前顯式命名字段開始,逐步向內查找匿名字段成員。如匿名字段成員被外層同名字段遮蔽,那么必須使用顯式字段名
func main() {type file struct {name string}type data struct {filename string // 與匿名字段 file.name 重名}d := data{name: "data",file: file{"file"},}d.name = "data2" // 訪問 data.named.file.name = "file2" // 使用顯式字段名訪問data.file.namefmt.Println(d.name, d.file.name)fmt.Printf("%#v\n", d) }如果多個相同層次的匿名字段成員重名,就只能使用顯式字段名訪問,因為編譯器無法確 認正確目標
func main() {type file struct {name string}type log struct {name string}type data struct {file // file和log層次相同log // file.name 和 log.name 重名}d := data{}d.name = "name" // 錯誤:ambiguous selector d.named.file.name = "file"d.log.name = "log" }嚴格來說,Go并不是傳統意義上的面向對象編程語言。匿名字段不是繼承機制,也無法 做多態處理。雖然配合方法集,可以用接口來實現一些類似的調用操作,但其本質是完全不同的
結構體與數組:
結構體數組定義:
// 數組需要要指定長度 var 結構體數組名[索引] 結構體類型 = [索引] 結構體類型{}數組修改結構體成員的值:
結構體數組名[索引].成員=值演示:
func structDemo02() {var arr [3]Student = [3]Student{Student{001, "itzhuzhu", 23, "廣州"},Student{002, "itzhuzhu2", 23, "廣州2"},Student{003, "itzhuzhu3", 23, "廣州3"},}fmt.Println(arr) //[{1 itzhuzhu 23 廣州} {2 itzhuzhu2 23 廣州2} {3 itzhuzhu3 23 廣州3}]fmt.Println(arr[0]) //{1 itzhuzhu 23 廣州}fmt.Println(arr[0].name, arr[0].age) //itzhuzhu 23//結構體數組名[索引].成員=值arr[0].addr = "深圳"fmt.Println("成員值修改后", arr[0]) //{1 itzhuzhu 23 深圳}// 通過循環輸出結構體數組中的內容for i := 0; i < len(arr); i++ {fmt.Println("通過循環輸出結構體數組全部的內容:", arr[i])fmt.Println("通過循環輸出結構體數組指定的內容:", arr[i].id)}for key, value := range arr {fmt.Println("key:", key)fmt.Println("value:", value)fmt.Println("打印指定內容:", value.age)} }結構體與切片:
和數組的玩法一樣,除了定義格式稍微不同
結構體切片定義:
var 結構體數組名[] 結構體類型 = [] 結構體類型{}切片修改結構體成員的值:
結構體切片名[索引].成員=值演示:
func structDemo03() {var arr []Student = []Student{Student{001, "itzhuzhu", 23, "廣州"},Student{002, "itzhuzhu2", 23, "廣州2"},Student{003, "itzhuzhu3", 23, "廣州3"},}fmt.Println(arr) //[{1 itzhuzhu 23 廣州} {2 itzhuzhu2 23 廣州2} {3 itzhuzhu3 23 廣州3}]fmt.Println(arr[0]) //{1 itzhuzhu 23 廣州}fmt.Println(arr[0].name, arr[0].age) //itzhuzhu 23//結構體數組名[索引].成員=值arr[0].addr = "深圳"fmt.Println("成員值修改后", arr[0]) //{1 itzhuzhu 23 深圳}// 通過循環輸出結構體數組中的內容for i := 0; i < len(arr); i++ {fmt.Println("通過循環輸出結構體切片全部的內容:", arr[i])fmt.Println("通過循環輸出結構體切片指定的內容:", arr[i].id)}for key, value := range arr {fmt.Println("key:", key)fmt.Println("value:", value)fmt.Println("打印指定內容:", value.age)}// 追加數據arr = append(arr, Student{004, "itzhuzhu4", 23, "佛山"})fmt.Println(arr) }結構體與map:
結構體map的定義:
make(map[key的類型]value的類型)演示:
func structDemo04() {m := make(map[int]Student)m[0] = Student{001, "itzhuzhu", 23, "廣州"}m[1] = Student{002, "itzhuzhu2", 23, "廣州"}m[2] = Student{003, "itzhuzhu3", 23, "廣州"}fmt.Println("全部數據:", m)fmt.Println("指定索引數據:", m[0])fmt.Println("指定索引成員數據:", m[0].name)delete(m, 0)for key, value := range m {fmt.Println("key:", key)fmt.Println("value:", value)fmt.Println("value.name:", value.name)fmt.Println("value.name:", value.name)} }結構體作為函數參數:
在函數中修改結構體成員值,是不會影響到原結構體的
創建格式:
func 函數名(結構體){函數體 }調用格式:
函數名(結構體)演示:
func main() {stu := Student{001, "itzhuzhu", 23, "廣州"}structDemo05(stu)fmt.Println(stu) }func structDemo05(stu Student) {// 修改結構體的成員,不會影響到原結構體stu.id = 999fmt.Println(stu) }求最大學生年齡:
鍵盤錄入學生信息,然后判斷年齡最大的學生,打印出年齡最大的學生信息
演示:
func main() {stu := make([]Student, 3)structDemo06(stu) }func structDemo06(stu []Student) {//定義年齡最大的變量max := stu[0].age//定義年齡最大的學生索引var maxIndex intfor i := 0; i < len(stu); i++ {fmt.Printf("請輸入第%d個學生的詳細信息\n", i+1)//切片是Student的類型,Student中有多個成員,所以要把里面的每個成員都賦值fmt.Scan(&stu[i].id, &stu[i].name, &stu[i].age, &stu[i].addr)// 如果大于最大年齡就重新賦值,然后把最大年齡的學生索引給定義的變量賦值if stu[i].age > max {max = stu[i].agemaxIndex = i}}fmt.Println(stu[maxIndex]) }結構體添加方法:
主要結構體類型不一樣,方法是可以重名的,算是不同的方法
一般寫方法的時候都會將結構體類型寫為指針類型的
格式:
// 表示是為某一個結構體添加的方法 func (結構體簡稱 結構體)方法名 (參數列表)(返回值列表){代碼 }調用格式:
對象名.方法演示:
func main() {stu := Student{"itzhuzhu", 24, 100}stu.show() //{itzhuzhu 222 100}fmt.Println(stu) //{itzhuzhu 24 100} }type Student struct {name stringage intscore float64 }// 普通方法是不會改變原來結構體的值的,除非是指針類型 func (student Student) show() {student.age = 222fmt.Println(student) }// 改成指針類型就會將person的數據改變 func (person *Person) show() {person.age = 222fmt.Println(person) }總結
以上是生活随笔為你收集整理的Golang——结构体创建与初始化、结构体与数组、结构体与切片、结构体与map、结构体作为函数参数、结构体方法、结构体方法继承的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java 工厂模式详解_java 工厂模
- 下一篇: java ztree json_java