一、結構體
結構體是一系列屬性的集合(類似于 Python 中的類)
1、結構體的定義與使用
// 定義
type Person struct {
Name string
Age int
Sex string
}
func main() {
// 使用
var per Person
per.Name="XiaoYang"
fmt.Println(per)
}
2、定義并賦初值
type Person struct {
Name string
Age int
Sex string
}
func main() {
var per1 Person = Person{Name: "XiaoYang"} // 按關鍵字傳參,可以少傳
var per2 Person = Person{"Bob", 20, "男"} // 按位置傳參,全傳
fmt.Println(per1) // 輸出:{XiaoYang 0 }
fmt.Println(per2) // 輸出:{Bob 20 男}
}
3、匿名結構體(只使用一次,沒有名字)
// 定義個匿名結構體并實體化之后賦值給了 hobby 變數
hobby := struct {
HobbyId int
HobbyName string
}{HobbyId: 1, HobbyName: "籃球"}
fmt.Println(hobby) // 輸出:{1 籃球}
fmt.Println(hobby.HobbyName) // 輸出:籃球
4、結構體的零值
定義好的結構體沒有被初始化時,該結構體的欄位將默認賦值為零值
也就是我屬性的零值,所以他是值型別,引數傳遞,copy 傳遞,在函式中修改不會影響原來的
type Person struct {
Name string
Age int
Sex string
}
func main() {
var per Person=Person{"Bob", 20, "男"}
fmt.Println(per) // 輸出:{Bob 20 男}
test(per) // 輸出:{Bob 20 男}
fmt.Println(per) // 輸出:{Bob 20 男}
}
func test(per Person) {
per.Age=20
fmt.Println(per)
}
5、結構體的指標
// & 放在變數前,表示取該變數的地址
// * 放在型別前,表示指向該型別的指標(變數定義,指定型別時才會用到) *[3]int 和 [3]*int
// * 放在變數前,表示解參考(取出指標指向的具體的值)
type Person struct {
Name string
Age int
Sex string
}
func main() {
var per1 *Person
fmt.Println(per1) // 輸出:<nil> 表示指標型別
// 定義并初始化
var per2 *Person = &Person{}
fmt.Println(per2) // 輸出:&{ 0 }
// 把per2的名字改成XiaoYang
(*per2).Name = "XiaoYang"
// 也支持直接使用
per2.Name = "Bob"
fmt.Println(per2) // 輸出:&{Bob 0 }
}
6、匿名欄位(欄位沒有名字,只有型別)
可用于【變數提升 / 提升欄位】類似于面向物件的繼承
// 定義一個結構體,匿名欄位型別就是欄位名字,所有型別不能重復
type Person struct {
string
int
Sex string
}
func main() {
per := Person{"XiaoYang", 20, "男"} // 欄位匿名,型別就是欄位名
fmt.Println(per) // 輸出:{XiaoYang 20 男}
fmt.Println(per.string) // 輸出:XiaoYang
}
7、嵌套結構體(結構體中套結構體)
type Person struct {
Name string
Age int
Sex string
Hobby Hobby // Person中嵌套Hobby結構體欄位
}
type Hobby struct {
HobbyId int
HobbyName string
}
func main() {
per := Person{Name:"XiaoYang", Age: 20, Sex: "男", Hobby: Hobby{1,"籃球"}}
fmt.Println(per) // 輸出:{XiaoYang 20 男 {1 籃球}}
fmt.Println(per.Name) // 輸出:XiaoYang
fmt.Println(per.Hobby.HobbyName) // 輸出:籃球
}
8、欄位提升
結構體中有匿名的結構體型別欄位,則該匿名結構體里的欄位就稱為提升欄位,可以從外部直接訪問
type Person struct {
Name string
Age int
Sex string
Hobby // Person中嵌套Hobby匿名結構體欄位
}
type Hobby struct {
HobbyId int
HobbyName string
}
func main() {
per := Person{Name:"XiaoYang", Age: 20, Sex: "男", Hobby: Hobby{1,"籃球"}}
// 列印愛好的名字(Hobby是一個匿名欄位,會欄位提升)
fmt.Println(per.HobbyName) // 輸出:籃球
// per.hobby 類似于面向物件中的super()
fmt.Println(per.Hobby.HobbyName) // 輸出:籃球
}
// ------------------------------------------------------------------------------------
// 當子類和父類中的欄位名一樣時,就像面向物件的繼承,子類繼承父類(結構體嵌套,匿名欄位),子類可以直接呼叫父類中的屬性或方法
type Person struct {
Name string
Age int
Sex string
Hobby // Person中嵌套Hobby匿名欄位
}
type Hobby struct {
HobbyId int
Name string
}
func main() {
per := Person{Name:"XiaoYang", Age: 20, Sex: "男", Hobby: Hobby{1,"籃球"}}
fmt.Println(per.Name) // 輸出:XiaoYang ——>優先使用自己的
fmt.Println(per.Hobby.Name) // 輸出:籃球 ——>指定列印Hobby的名字
}
9、結構體相等性
結構體是值型別,
如果它的每一個欄位都是可比較的,則該結構體也是可以比較的,
如果兩個結構體變數的對應欄位相等,則兩個變數也是相等的,
如果結構體包含不可比較的欄位,則結構體變數也不可比較,
type Person struct {
Name string
Age int
Sex string
// 包含不可比較的欄位
Test []int ——>這是參考型別不可比較
}
func main() {
// 值型別可以直接==比較,參考型別只能跟nil用==比較
per1 := Person{Name: "XiaoYang"}
per2 := Person{Name: "XiaoYang"}
per3 := Person{Name: "XiaoYang", Age: 20}
fmt.Println(per1 == per2) // 輸出:ture ——>包含不可比較型別都會直接報錯
fmt.Println(per1 == per3) // 輸出:false
}
二、方法
方法就是一個特殊函式,在函式的基礎上加了一些東西
在func這個關鍵字和方法名中間加入一個特殊的接收器型別,接收器可以是結構體型別,也可以是非結構體型別
1、方法的定義和使用
type Person struct {
Name string
Age int
Sex string
}
// 定義一個方法:給Person結構體系結一個方法,oneself(名字隨便取)類似于Python類中的self
func (oneself Person) printName() {
// 在方法內使用oneself
fmt.Println(oneself.Name)
}
func main() {
// 使用,物件呼叫方法
per := Person{}
per.Name = "XiaoYang"
// 系結給物件的方法
per.printName() // 輸出:XiaoYang
}
2、有了函式為啥還需要方法?
方法功能都能實作,但是呢?它就能指定給某個物件了 ,
type Person struct {
Name string
Age int
Sex string
}
// 方法
func (oneself Person) printName() {
fmt.Println(oneself.Name)
}
// 函式
func printName(oneself Person) {
fmt.Println(oneself.Name)
}
func main() {
per := Person{Name: "XiaoYang"}
per.printName() // 方法的特殊之處,可以自動傳遞值
printName(per) // 函式需要手動傳遞值
}
3、指標接收器與值接收器
type Person struct {
Name string
Age int
Sex string
}
// 值接收器修改名字
func (oneself Person) changeName(name string) {
oneself.Name = name
}
// 指標接收器修改年齡
func (oneself *Person) changeAge(age int) {
oneself.Age = age
}
func main() {
per := Person{Name: "XiaoYang", Age: 20}
fmt.Println(per) // 輸出:{XiaoYang 20 }
per.changeName("Bob")// 由于這個是值接收器,它是copy一份傳遞過去所以修改的是copy的不會改掉原來的
per.changeAge(18) // 指標接收器,它傳遞的是指標
fmt.Println(per) // 輸出:{XiaoYang 18 }
}
/*
什么時候用指標接收器,什么時候使用值接收器:
-想改原來的,就用指標
-不想改原來的,就用值
*/
5、匿名欄位的方法(方法提升)
type Person struct {
Name string
Age int
Sex string
Hobby // 匿名欄位
}
type Hobby struct {
Id int
Name string
}
// 列印Person的名字
func (oneself Person) printName() {
fmt.Println(oneself.Name)
}
// 列印Hobby的名字
func (oneself Hobby) printHobbyName() {
fmt.Println(oneself.Name)
}
// 列印Hobby的名字
func (oneself Hobby) printName() {
fmt.Println(oneself.Name)
}
func main() {
per := Person{Name: "XiaoYang", Hobby: Hobby{1, "籃球"}}
per.printName() // 輸出:XiaoYang
per.printHobbyName() // 輸出:籃球
// 如果方法重名了,優先使用結構體自己的
per.printName() // 輸出:XiaoYang
per.Hobby.printName() // 輸出:籃球
}
6、在方法中使用值接收器 與 在函式中使用值引數
type Person struct {
Name string
Age int
Sex string
}
// 在方法中使用值接收器
func (oneself Person) printName() {
fmt.Println(oneself.Name)
}
// 在函式中使用值引數
func printName(oneself Person) {
fmt.Println(oneself.Name)
}
func main() {
per1 := &Person{Name: "XiaoYang"} // per1是個指標
per2 := Person{Name: "Bob"}
printName(*per1) // 輸出:XiaoYang
per1.printName() // 輸出:XiaoYang ———> 值收器:可以用值來調,也可以用指標來調
per2.printName() // 輸出:Bob
}
7、在方法中使用指標接收器 與 在函式中使用指標引數
type Person struct {
Name string
Age int
Sex string
}
// 在方法中使用指標接收器
func (oneself *Person) printName() {
fmt.Println(oneself.Name)
}
func (oneself *Person)changeName(name string) {
oneself.Name=name
}
// 在函式中使用指標引數
func printName(oneself *Person) {
fmt.Println(oneself.Name)
}
func main() {
per1 := Person{Name: "XiaoYang"}
per2 := &Person{Name: "Bob"} // per1是個指標
per1.printName() // 值可以呼叫
printName(&per1)
per2.printName() // 指標可以呼叫
printName(per2)
per1.changeName("Alen") // 可以修改
fmt.Println(per1)
per2.changeName("YS") // 可以修改
fmt.Println(per2)
}
/*
總結:
-不管是值型別接收器還是指標型別接收器,都可以用值來呼叫,或者指標來呼叫,
-不管是值還是指標來呼叫,只要是值型別接收器,改的就是新的,只要是指標型別接收器,改的是原來的,
*/
8、非結構體上系結方法
不允許在基礎資料型別上系結方法(如:int、string ... )
但是自己定義的型別可以系結方法
type Myint int
func (i *Myint) add() {
(*i)++
}
func main() {
var a Myint = 10
fmt.Println(a) // 輸出:10
a.add()
a.add()
a.add()
fmt.Println(a) // 輸出:13
}
學習之旅
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/306140.html
標籤:其他
