結構體嵌套
golang
中沒有類,他通過結構體來實現其他編程語言中類的相關功能。
具名結構體
基本語法
基本語法
golang
的結構體嵌套特別簡單。
type 結構體類型1 struct{字段 類型1字段 類型2
}//這樣就實現了結構體的嵌套
type 結構體類型2 struct{字段 類型1字段 類型2字段 結構體類型1
}
舉例
package struct_knowledgeimport "fmt"type Worker struct{salary intprofession string
}
//具名嵌套結構體
type Human struct{Name stringAge int Work Worker
}func (w Worker) GetSalary(){fmt.Printf("工資為%d\n",w.salary)
}//訪問具名結構體
func VisitNestingStruct(){var human Human//訪問字段/*報錯:human.salary undefined(type Human has no filed or method GetSalary)*///human.salary = 25//通過字段連鎖訪問human.Work.salary = 20fmt.Printf("結構體的實例為%v\n",human)//通過字面量訪問human = Human{Age: 20,Name: "張三",Work: Worker{salary: 1000,profession: "no work",},}fmt.Printf("結構體的實例為%v\n",human)//通過位置賦值human = Human{"lisa",45,Worker{salary: 10000,profession: "waiter",},}fmt.Printf("結構體的實例為%v\n",human)// 調用方法/*報錯:human.GetSalary undefined(type Human has no filed or method GetSalary)*/// human.GetSalary()human.Work.GetSalary()
}
結果
結構體的實例為struct_knowledge.Human{Name:"", Age:0, Work:struct_knowledge.Worker{salary:20, profession:""}}
結構體的實例為struct_knowledge.Human{Name:"張三", Age:20, Work:struct_knowledge.Worker{salary:1000, profession:"no work"}}
結構體的實例為struct_knowledge.Human{Name:"lisa", Age:45, Work:struct_knowledge.Worker{salary:10000, profession:"waiter"}}
工資為10000
訪問規則
具名嵌套結構體的訪問只能通過
嵌套結構體字段名.字段
嵌套結構體字段名.方法()
不能通過最外層結構體直接訪問。
舉例
type Worker struct{salary intprofession string
}
//具名嵌套結構體
type Human struct{Name stringAge int Work Worker
}
Human實例不能直接訪問Worker實例的字段或方法,需要通過
Human實例.Work.字段
Human實例.Work.方法
匿名結構體
基本語法
就是不寫用字段接收嵌套結構體而是直接寫類型名,例如
type 結構體類型A struct{字段1 類型1字段2 類型2...
}type 結構體類型B struct{字段1 類型1結構體類型A
}
舉例
package struct_knowledgeimport "fmt"type StructA struct{name stringage int
}type StructB struct{price int StructA
}func VisitStructB(){var st StructBfmt.Printf("嵌套結構體的值為%#v\n",st)
}
結果
嵌套結構體的值為struct_knowledge.StructB{price:0, StructA:struct_knowledge.StructA{name:"", age:0}}
訪問規則
名稱訪問
匿名結構體如果我們將他按照匿名字段理解,那么他就可以解析成如下形式:
type 結構體類型A struct{字段1 類型1字段2 類型2...
}type 結構體類型B struct{字段1 類型1結構體類型A
}
//按照匿名字段理解
type 結構體類型B struct{字段1 類型1結構體A 結構體類型A
}
所以我們仍然可以通過如下形式修改和訪問:
結構體B實例.結構體A.字段
結構體B實例.結構體A.方法()
舉例
package struct_knowledgeimport "fmt"type StructA struct{name stringage int
}type StructB struct{price int StructA
}/*我們可以按照訪問具名結構體的方法訪問匿名結構體的名字就是 類型同名
*/
func VisitStructByName(){var st StructB//連鎖訪問st.StructA.age = 25fmt.Printf("結構體的實例為%#v\n",st)//字面量訪問st = StructB{price: 1000,StructA: StructA{age:25,name:"lisi",},}fmt.Printf("結構體的實例為%#v\n",st)//位置訪問st = StructB{1000,StructA{age:30,name:"sam",},}fmt.Printf("結構體的實例為%#v\n",st)
}
結果
結構體的實例為struct_knowledge.StructB{price:0, StructA:struct_knowledge.StructA{name:"", age:25}}
結構體的實例為struct_knowledge.StructB{price:1000, StructA:struct_knowledge.StructA{name:"lisi", age:25}}
結構體的實例為struct_knowledge.StructB{price:1000, StructA:struct_knowledge.StructA{name:"sam", age:30}}
直接訪問
匿名結構體與具名結構體最大的不同就是:
我們可以直接通過外層結構體訪問匿名結構體的字段或方法(前提沒有產生同名沖突)。
舉例
package struct_knowledgeimport "fmt"type StructA struct{name stringage int
}type StructB struct{price int StructA
}func (c StructA) GetAge(){fmt.Printf("StructA的年齡為%v\n",c.age)
}func VisitStructByNoName(){var st StructB//在不出現名字沖突的情況下,外層結構體可以直接訪問匿名結構體的字段和方法st.age = 25st.GetAge()fmt.Printf("結構體的實例為%#v\n",st)//但僅限于這種成員訪問,字面量和位置就不適用/*報錯:unknow field age in struct literal of type StructBunknow field name in struct literal of type StructB*/// st = StructB{// price: 1000,// age:30,// name:"lisa",// }
}
結果
StructA的年齡為25
結構體的實例為struct_knowledge.StructB{price:0, StructA:struct_knowledge.StructA{name:"", age:25}}
字段沖突
這種情況主要出現在匿名結構體中,因為同一結構體中字段唯一,所以結構體中不能出現同名字段。
但是匿名結構體嵌套后,由于他可以匿名訪問,所以就產生了字段和方法沖突。
這也是匿名結構體允許具名訪問的原因。
解決方案
當出現字段沖突時,訪問匿名結構體的同名字段或方法需要采用具名訪問。
舉例
package struct_knowledgeimport "fmt"type StructOne struct{name string age intprice int
}type StructTwo struct{name string age int
}type StructThree struct{name stringStructOneStructTwo
}func VisitStructThree(){var st StructThreefmt.Printf("結構體的實例為%#v\n",st)//訪問不同名字段,可以直接匿名訪問st.price = 20/*但是訪問同名字段或方法,就需要指明結構體如果最外層結構體有就訪問的是最外層*/st.name = "lisa"/*如果訪問同名字段或方法,但最外層結構體也沒有就會報錯ambiguous selector st.age*/// st.age = 25
}
結果
結構體的實例為struct_knowledge.StructThree{name:"", StructOne:struct_knowledge.StructOne{name:"", age:0, price:0}, StructTwo:struct_knowledge.StructTwo{name:"", age:0}}
結構體的實例為struct_knowledge.StructThree{name:"lisa", StructOne:struct_knowledge.StructOne{name:"", age:0, price:20}, StructTwo:struct_knowledge.StructTwo{name:"", age:0}}
沖突字段訪問規則
1.如果要訪問的同名字段或者方法頂層有,直接訪問則采用頂層的字段或方法。
2.如果要訪問的同名字段或者方法頂層沒有,直接訪問就會報錯。
# ambiguous的中文含義:模糊不清的,模棱兩可的
ambiguous selector st.xxx
解決字段沖突問題
要訪問嵌套結構體的同名字段或者方法,可以采用具名訪問法,例如
外層結構體實例.匿名結構體類型.字段
外層結構體實例.匿名結構體類型.方法()