go元是一種靜態(tài)類型的編程語言。這意味著拂酣,編譯器需要在編譯時(shí)知曉程序里每個(gè)值的類型秋冰。如果提前知道類型信息,編譯器就可以確保程序合理地使用值婶熬。這有助于減少潛在的內(nèi)存異常和bug丹莲,并且使編譯器有機(jī)會對代碼進(jìn)行一些性能優(yōu)化,提高執(zhí)行效率尸诽。
用戶定義的類型
go語言中最常用的方法是使用關(guān)鍵字
struct
聲明一個(gè)新的結(jié)構(gòu)類型甥材,以關(guān)鍵字type
開始,之后是新類型的名字性含,最后是關(guān)鍵字struct
洲赵。
// user 在程序里定義一個(gè)用戶類型
type user struct {
name string
email string
ext int
privileged bool
}
關(guān)鍵字var
創(chuàng)建了類型user
,且名為bill
的變量商蕴。
注:當(dāng)聲明一個(gè)變量時(shí)叠萍,該變量對應(yīng)的值總會被初始化。這個(gè)值要么用指定的值初始化绪商,要么用零值做初始化苛谷。如這里的bill
變量,其中的屬性如果是數(shù)值類型格郁,零值就是0腹殿;如果類型是字符串,零值就是空字符串例书;如果是布爾類型锣尉,零值是false。
//聲明user類型的變量
var bill user
聲明一個(gè)user類型變量决采,并使用非零值作為初始值自沧。符號:=
表示短變量聲明操作符。主要負(fù)責(zé)兩件事:聲明一個(gè)變量树瞭,并初始化拇厢。
//聲明user類型的變量,并初始化所有字段
lisa := user {
name : "Lisa",
email : "lisa@email.com",
ext : 123,
privileged: true,
}
//另一種聲明并初始化的方式晒喷,不使用結(jié)構(gòu)字面量孝偎。
//但是要注意字段順序
baker := user{"Baker", "baker@email.com", 123, true}
使用其它自定義的結(jié)構(gòu)類型作為字段類型
//admin需要一個(gè)user類型作為管理者,并附加權(quán)限
type admin struct {
person user
level string
}
此時(shí)厨埋,當(dāng)聲明的字段有其它自定義的結(jié)構(gòu)類型時(shí)邪媳,初始化也會有一些不同捐顷。
fred := admin{
person: user{
name: "Jon",
email: "jon@email.com",
ext: 12333,
privileged: true,
},
level: "super",
}
log.Println("==================fred====================")
log.Println(fred.level)
log.Println(fred.person)
//2017/08/13 22:39:08 ==================fred====================
//2017/08/13 22:39:08 super
//2017/08/13 22:39:08 {Jon jon@email.com 12333 true}
方法
方法能給用戶定義的類型添加新的行為荡陷。方法實(shí)際上也是函數(shù)雨效,只是在聲明的時(shí)候,在關(guān)鍵字
func
和方法名之間增加了一個(gè)參數(shù)废赞。
type user struct {
name string
email string
}
// notify 使用值接收者實(shí)現(xiàn)一個(gè)方法
func (u user) notify() {
fmt.Printf("Sending user Email To %s<%s>\n", u.name, u.email)
}
// changeEmail 使用指針接收者實(shí)現(xiàn)了一個(gè)方法
func (u *user) changeEmail(email string) {
u.email = email
}
func UserMethod() {
//user類型的值可以調(diào)用使用值接收者聲明的方法
bill := user{"Bill", "bill@email.com"}
bill.notify() //Sending user Email To Bill<bill@email.com>
//指向user類型的指針也可以調(diào)用使用值接收者聲明的方法
lisa := &user{"Lisa", "lisa@email.com"}
lisa.notify() //Sending user Email To Lisa<lisa@email.com>
//user類型的值可以調(diào)用使用指針接收者聲明的方法
bill.changeEmail("billNew@email.com")
bill.notify() //Sending user Email To Bill<billNew@email.com>
//指向user類型值的指針可以調(diào)用使用指針接收者聲明的方法
lisa.changeEmail("lisaNew@email.com")
lisa.notify() //Sending user Email To Lisa<lisaNew@email.com>
}
到這徽龟,其實(shí)可以看出這和Java當(dāng)中的class
類聲明對象和方法大同小異。但是go
語言中多了接收者這個(gè)概念唉地,且分為兩種:
- 值接收者
- 指針接收者
代碼剖析
- 值接收者聲明方法與調(diào)用
//notify方法的接收者据悔,被聲明為user類型的值
//使用值接收者聲明方法,調(diào)用時(shí)耘沼,會使用這個(gè)值的一個(gè)副本來執(zhí)行
func (u user) notify()
//bill是user類型的變量名极颓,方法notify會接收到bill的值的一個(gè)副本
bill.notify()
- 指針變量 調(diào)用 值接收者聲明的方法
//指針變量lisa 調(diào)用 值接收者聲明的方法notify()
lisa.notify()
//go語言在背后實(shí)際執(zhí)行的動作,但有一點(diǎn)始終沒變群嗤,
//就是notify調(diào)用的一直是值的副本
//這里也是調(diào)用的指針指向的值的副本
(*lisa).notify()
- 指針接收者申明的方法與調(diào)用
//該方法使用指針接收者聲明
//接收者的類型是指向user類型值的指針菠隆,而不是user類型的值
func (u *user) changeEmail(email string)
//當(dāng)調(diào)用使用指針接收者聲明的方法時(shí),這個(gè)方法會共享調(diào)用方法時(shí)接收者所指向的值
lisa.changeEmail("lisaNew@email.com")
- 普通變量 調(diào)用 指針接收者聲明的方法
//普通變量bill 調(diào)用 指針接收者聲明的方法changeEmail
bill.changeEmail("billNew@email.com")
//go也做了調(diào)整狂秘,實(shí)際動作如下
(&bill).changeEmail("billNew@email.com")
總結(jié)兩點(diǎn):
- 值接收者使用值的副本來調(diào)用方法骇径,而指針接收者使用實(shí)際值來調(diào)用方法。
- 普通變量和指針變量 都能調(diào)用不同聲明類型的方法者春,實(shí)際是否影響原值破衔,需判斷方法的接收者是指針接收者還是值接收者。