定義一個結(jié)構(gòu)體,將函數(shù)和結(jié)構(gòu)體綁定在一起的東西就是方法
格式:
func (接收者名稱 接收者類型)函數(shù)名稱(形參列表)(返回值列表){
邏輯語句;
}Go語言中的函數(shù)可以和任何類型綁定, 但是一般用于和結(jié)構(gòu)體綁定
-
注意點:
1.方法和函數(shù)的區(qū)別在于, 函數(shù)可以直接調(diào)用(通過包名.函數(shù)名稱), 而方法只能通過綁定的數(shù)據(jù)類型對應(yīng)的變量來調(diào)用(變量.函數(shù)名稱)
2.函數(shù)名稱和方法名稱可以重名
type Person struct{
name string
age int
}
func (Person)say(){
fmt.Printf("Hello")
}
p := Person{"xxz",18}
p.say()//"Hello"
- 如果指定了接收者名稱,那么調(diào)用方法時會將調(diào)用者傳遞給接收者
- 簡單理解:可以把接收者看做函數(shù)的形參
- 以下第一段代碼表示的是值傳遞
type Person struct{
name string
age int
}
func (per Person)say(){
fmt.Println("Hello",per.name)
}
p := Person{"xxz",18}
p.say()//"Hello xxz"
- 以下代碼為地址傳遞
- 如果為以下代碼,那么編譯器會自動將結(jié)構(gòu)體的地址取出來傳遞給函數(shù)
type Person struct{
name string
age int
}
func (per *Person)setAge(age int){
per.age = age
}
per := Person{"xxz",18}
per.say()//"Hello xxz"
//p := &per
//(*p).setAge(666)
per.setAge(666) // 底層相當(dāng)于(&per).setAge(666)
fmt.Println(per)//{"xxz",666}
Go語言接口
-
1.如何定義一個接口
type USB interface {
函數(shù)名稱(形參列表)(返回值列表)
函數(shù)名稱(形參列表)(返回值列表)
} 接口內(nèi)只實現(xiàn)了函數(shù)的聲明,沒有實現(xiàn)
Go語言中實現(xiàn)一個接口, 不需要做額外的聲明, 只要某種數(shù)據(jù)類型綁定了所有接口中的方法就是實現(xiàn)了這個接口
-
實現(xiàn)接口之后的特性
只要某種數(shù)據(jù)類型實現(xiàn)了接口, 那么就可以使用接口變量保存這種數(shù)據(jù)類型
只要某種數(shù)據(jù)類型實現(xiàn)了接口, 那么就可以使用接口變量調(diào)用接口中聲明的方法
/*
需求:定義一個函數(shù),實現(xiàn)電器的打開和關(guān)閉
*/
type USB interface{
start()
end()
}
type Computer struct{
name string
}
func (c Computer)start(){
fmt.Println(c.name,"被打開了")
}
func (c Computer)end(){
fmt.Println(c.name,"被關(guān)閉了")
}
type Phone struct{
name string
}
func (ph Phone)start(){
fmt.Println(ph.name,"被打開了")
}
func (ph Phone)end(){
fmt.Println(ph.name,"被關(guān)閉了")
}
func main(){
var in USB
var cm Computer = Computer{"三星"}
Option(cm)
var ph Phone = Phone{"蘋果"}
Option(ph)
}
function Option(in USB){
in.start()
in.end()
}
-
注意點
1.接口中只能有方法的聲明, 不能有方法的實現(xiàn)2.接口中只能有方法的聲明, 不能有變量的聲明
3.只有實現(xiàn)了接口中聲明的所有方法, 才算實現(xiàn)了接口, 才能使用接口變量保存
4.在實現(xiàn)接口的時候, 方法名稱,形參列表,返回值列表必須一模一樣
5.接口和結(jié)構(gòu)體一樣, 可以嵌套
6.接口和結(jié)構(gòu)體一樣, 嵌套時不能嵌套自己(自己搞自己)
7.可以將集接口變量賦值給子集接口變量,不可以將子集接口變量賦值給超集接口變量(無論實際的數(shù)據(jù)類型是否已經(jīng)實現(xiàn)了超集的所有方法)
8.接口中不能出現(xiàn)同名的方法聲明
空接口
- 空接口相當(dāng)于其他語言的Object類型
- 空接口可以保存任何類型的數(shù)據(jù)
var value interface{}
- 數(shù)組和字典一般是用來保存相同類型數(shù)據(jù)的,但是我們可以利用空接口使它們保存不同的類型的數(shù)據(jù)
var arr [3]interface{}
arr[0] = 1
arr[1] = "lnj"
arr[2] = false
fmt.Println(arr)
接口類型轉(zhuǎn)換(類型斷言)
- 當(dāng)一個結(jié)構(gòu)體實現(xiàn)了中所有的方法,那么我們稱這個結(jié)構(gòu)體實現(xiàn)了這個接口
- 當(dāng)一個結(jié)構(gòu)體實現(xiàn)了這個接口,我們可以通過接口變量來保存這個結(jié)構(gòu)體變量
- 當(dāng)這個接口變量保存了這個結(jié)構(gòu)體變量,那么可以通過調(diào)用接口的方法來實現(xiàn)結(jié)構(gòu)體調(diào)用這個方法
- 但是接口變量不能調(diào)用接口中沒有的方法,也不能調(diào)用結(jié)構(gòu)體的屬性,要想調(diào)用接口以外的方法和變量,我們只能通過接口類型轉(zhuǎn)換來實現(xiàn)
- 方法一:
通過value,ok := 接口變量名稱.(具體數(shù)據(jù)類型) - 轉(zhuǎn)換成功ok值為True,value拿到轉(zhuǎn)換后的結(jié)構(gòu)體
- 轉(zhuǎn)換的類型和接口保存的類型不一樣時ok為false
type USB interface{
start()
}
type Computer struct{
name string
}
func (cm Computer)start(){
fmt.Println(cm.name,"被打開了")
}
func main(){
var cm Computer = Computer{"華碩"}
in USB := cm
//fmt.Println(in.name) 報錯
value,ok := in.(Computer)
fmt.Println(value.name)//"華碩"
fmt.Println(ok)//True
}
- 方法二
通過 value := 接口變量名.(type)配合switch - 會將接口類型變量轉(zhuǎn)換為對應(yīng)的原始類型之后賦值給value
cm := 接口變量名.(type)
switch cm := in.(type) {
case Computer:
fmt.Println(cm)
cm.say()
default:
fmt.Println("不是Person類型")
}
cm := Computer{"惠普"}
var sce []interface{} = []interface{}{1, 3.14, false, "lnj", cm}
// 需求: 獲取切片中保存的每一個數(shù)據(jù)的原始類型
for key, value := range sce {
switch temp := value.(type) {
case int:
fmt.Println("第",key, "個元素是int類型")
case float64:
fmt.Println("第",key, "個元素是float64類型")
case bool:
fmt.Println("第",key, "個元素是bool類型")
case string:
fmt.Println("第",key, "個元素是string類型")
case Computer:
fmt.Println("第",key, "個元素是Computer類型")
temp.say()
}
}
- 方法三:
定義一個類似與轉(zhuǎn)接口的空接口用來保存要調(diào)用的屬性或方法所在的結(jié)構(gòu)體的類型 - 第一種:把抽象接口類型轉(zhuǎn)換為具體的接口類型
- 第二種:把抽象的接口類型轉(zhuǎn)換為結(jié)構(gòu)體類型
var in interface{} = Computer{"華碩"}
//第一種
if value,ok := in.(USB);ok{
value.start()
}
//第二種
if value,ok := in.(Computer);ok{
value.start()
}