怎么做自建站長(zhǎng)沙疫情最新情況
本節(jié)內(nèi)容是面向?qū)ο蟮暮诵呐c基礎(chǔ),很重要。
注意:由于導(dǎo)包語(yǔ)句已經(jīng)在19講(筆記19:面向?qū)ο蟮囊?#xff09;展示過(guò)了,所以這里就不展示了。
一、方法的定義與細(xì)節(jié)
方法是與特定類(lèi)型(通常是結(jié)構(gòu)體)關(guān)聯(lián)的函數(shù)。方法可以操作該類(lèi)型的實(shí)例,并且可以使用其字段。定義方法時(shí),需要指定一個(gè)接收者(receiver),這使得方法能夠訪(fǎng)問(wèn)該接收者的屬性。語(yǔ)法如下:
func (receiver TypeName) MethodName(parameters) returnList {// 方法體
}
receiver是接收者的名稱(chēng),類(lèi)型是你想要關(guān)聯(lián)的自定義類(lèi)型(通常是結(jié)構(gòu)體)。
MethodName是方法的名稱(chēng)。
parameters是方法接受的參數(shù)。
returnList是返回值類(lèi)型列表。
首先,在utils中定義一個(gè)結(jié)構(gòu)體和一個(gè)方法:
type Circle struct {Radius float64
}// 定義一個(gè)方法,計(jì)算圓的面積
// 1. 方法中參數(shù)名字隨便起
// 2. 方法 Area 和結(jié)構(gòu)體 Circle綁定,必須在同包中定義!
func (c Circle) Area() float64 {return 3.14 * c.Radius * c.Radius
}
然后在main中調(diào)用:
func main() {// 創(chuàng)建一個(gè) Circle 實(shí)例circle := utils.Circle{Radius: 5}// 調(diào)用方法area := circle.Area()// 輸出結(jié)果fmt.Printf("Area: %.2f\n", area)
}
一些細(xì)節(jié)
1.如果其他類(lèi)型的變量調(diào)用area一定會(huì)報(bào)錯(cuò)。
2.結(jié)構(gòu)體對(duì)象傳入方法area中,屬于值傳遞,和參數(shù)傳遞一致。
3.receiver的類(lèi)型是你想要關(guān)聯(lián)的自定義類(lèi)型。
4.如果某個(gè)自定義類(lèi)型實(shí)現(xiàn)了返回string,名字為String()的方法(如果是同包內(nèi)調(diào)用,s可以小寫(xiě)),那么fmt包的Printf或Println函數(shù)打印該類(lèi)型時(shí),會(huì)自動(dòng)調(diào)用String()。
對(duì)于前兩點(diǎn),首先,在utils中定義另一個(gè)方法來(lái)演示值傳遞:
// 定義一個(gè)方法,演示值傳遞
func (c Circle) SetRadius(newRadius float64) {c.Radius = newRadiusfmt.Printf("Inside Radius: %.2f\n", c.Radius)
}
然后在main文件中調(diào)用:
type test struct {a int
}func main() {// 創(chuàng)建一個(gè) Circle 實(shí)例circle := utils.Circle{Radius: 5}// 調(diào)用方法area := circle.Area()fmt.Printf("Area: %.2f\n", area)// 1. 如果其他類(lèi)型變量調(diào)用 area 一定會(huì)報(bào)錯(cuò)// 下面的代碼將導(dǎo)致編譯錯(cuò)誤//t := test{}// t.area() // 這行會(huì)報(bào)錯(cuò),因?yàn)?radius 不是 Circle 類(lèi)型// 2. 結(jié)構(gòu)體對(duì)象傳入方法 Area 中,屬于值傳遞circle2 := utils.Circle{Radius: 10}fmt.Printf("Old Radius: %.2f\n", circle2.Radius)// 調(diào)用 SetRadius 方法嘗試修改半徑circle2.SetRadius(15)fmt.Printf("New Radius: %.2f\n", circle2.Radius) // 仍然是 10
}
OK,如果我就想在SetRadius內(nèi)改變r(jià)adius呢?那肯定是用指針了,但方法比數(shù)組指針簡(jiǎn)單:將SetRadius中的Circle前加上*即可,因?yàn)?strong>編譯器會(huì)自動(dòng)處理結(jié)構(gòu)體指針,所以在main中的代碼無(wú)需改動(dòng)!
對(duì)于第三點(diǎn),receiver的類(lèi)型是你想要關(guān)聯(lián)的自定義類(lèi)型,這也就是說(shuō),基本類(lèi)型不能作為方法中的接收類(lèi)型!讀者可自行嘗試,這里不做贅述。
對(duì)于第四點(diǎn),首先,在utils內(nèi)定義String():
func (p Person) String() string {str := fmt.Sprintf("name=%s,age=%v,sex=%s", p.Name, p.Age, p.Sex)return str
}
然后在main中調(diào)用:
func main() {p := utils.Person{Name: "李華", Age: 30, Sex: "女"}fmt.Printf("%v\n", p) // 使用格式化字符串fmt.Println(p) // 直接打印
}
這個(gè)String方法呢,也是定義結(jié)構(gòu)體時(shí)常用的,以便輸出結(jié)構(gòu)體信息。這里我提一個(gè)問(wèn)題:如果定義了Person的別名,打印其實(shí)例還會(huì)自動(dòng)調(diào)用String()嗎?驗(yàn)證很簡(jiǎn)單,讀者可自行嘗試,這里不做贅述。
二、方法與函數(shù)的區(qū)別
方法 | 函數(shù) | |
---|---|---|
和其他類(lèi)型的關(guān)系 | 綁定到特定類(lèi)型 | 獨(dú)立于任何類(lèi)型 |
語(yǔ)法 | func (receiver ReceiverType) MethodName(parameters) returnType | func FunctionName(parameters) returnType |
調(diào)用方式 | 通過(guò)類(lèi)型的實(shí)例調(diào)用 instance.MethodName() | 直接調(diào)用 FunctionName() |
作用域 | 可以訪(fǎng)問(wèn)綁定類(lèi)型的字段 | 只能訪(fǎng)問(wèn)傳入的參數(shù) |
指定類(lèi)型是否需要和傳入類(lèi)型一致 | 不需要(可以隨意傳入值或指針) | 需要 |
關(guān)于最后一點(diǎn),首先在utils中定義兩個(gè)接收者不同的方法:
// 方法:接收者為值類(lèi)型
func (p Person) PValue() {fmt.Println("Hello, my name is", p.Name)
}// 方法:接收者為指針類(lèi)型
func (p *Person) PPointer() {fmt.Println("Hello, my name is", p.Name)
}
然后在main文件中調(diào)用:
// 函數(shù):必須傳入 Person 類(lèi)型
func PrintPerson(p utils.Person) {fmt.Println("Person's name:", p.Name)
}func main() {// 創(chuàng)建值類(lèi)型和指針類(lèi)型的實(shí)例p1 := utils.Person{Name: "李華"}p2 := &utils.Person{Name: "張三"}p1.PPointer() // 調(diào)用接收者為指針的方法,傳入值類(lèi)型PrintPerson(p1) // 調(diào)用函數(shù),傳入值類(lèi)型p2.PValue() // 調(diào)用接收者為值類(lèi)型的方法,傳入指針PrintPerson(*p2) // 調(diào)用函數(shù),傳入解引用的指針
}
程序輸出如下:
Hello, my name is 李華
Person's name: 李華
Hello, my name is 張三
Person's name: 張三