Go中方法是作用在指定的數(shù)據(jù)類型上的,即必須和指定的數(shù)據(jù)類型綁定,因此自定義類型都可以具有方法,而不僅僅是結(jié)構(gòu)體。
方法聲明與調(diào)用
方法的定義
func (receiver type) methodName (argument_list) (return_value_list) {
// method body
return value
}
| 元素 | 描述 |
|---|---|
| argument_list | 參數(shù)列表,表示方法的輸入。 |
| receiver type | 表示方法和指定的type類型進行綁定,該方法作用于type類型。type可以是結(jié)構(gòu)體也可以是自定義類型。 |
| receiver | 是type類似的一個實例變量 |
| return_value_list | 返回值列表,表示返回的值,可以為多個。 |
| method_body | 方法體,為實現(xiàn)某功能的代碼塊。 |
| return |
return語句不是必須的 |
type User struct {
Id int
}
// 為User類型綁定TableName方法
func (t User) TableName() string {
fmt.Printf("%+v\n", t)
return "users"
}
func main() {
u := User{1}
name := u.TableName()
fmt.Println(name)
}
語法說明
-
func (t User) TableName(){}表示User類型具有一個方法,方法名稱為TableName。 -
(t User)體現(xiàn)了TableName方法是和User類型綁定的 -
TableName()方法只能通過User類型的變量來調(diào)用,而不能直接調(diào)用,也不能使用其它類型變量來調(diào)用。 -
(t User)中的t變量表示哪個User變量調(diào)用,這個t就是它的副本,類似函數(shù)傳參。 - 若需要傳入引用類型而不采用副本的方式可使用
(t *User)的方式 -
t這個名字由開發(fā)人員自行指定,不是固定的。
方法的調(diào)用和傳參機制
方法的調(diào)用和傳參機制和函數(shù)基本一致,不同之處在于方法調(diào)用時會將調(diào)用方法的變量作為實參也傳遞給方法,若變量是值類型則進行值拷貝,若變量是引用類型,則進行地址拷貝。
type Circle struct {
radius float64
}
func (t Circle) area() float64 {
return 3.14 * t.radius * t.radius
}
func main() {
var c Circle
c.radius = 4.0
res := c.area()
fmt.Println(res) // 50.24
}
由于采用值拷貝的方式效率較低,建議采用傳遞指針的方式以提升效率。
注意事項
- 結(jié)構(gòu)體類型是值類型,方法調(diào)用中遵守值類型的傳遞機制,即值類型采用的是值拷貝傳遞的方式。
- 若希望在方法中修改結(jié)構(gòu)體變量的值可通過結(jié)構(gòu)體指針的方式來處理
- Go中方法的作用是在指定的數(shù)據(jù)類型上(和指定的數(shù)據(jù)類型綁定),因此自定義類型都可以有方法,而不僅僅是結(jié)構(gòu)體,基本類型也可以擁有方法。
- 方法的訪問范圍控制的規(guī)則和函數(shù)一樣,方法名首字母小寫只能在本包訪問,首字母大寫可以在本包和其它包訪問。
- 若某個變量實現(xiàn)了
String()方法則fmt.Println()默認會調(diào)用此變量的String()方法進行輸出。
type User struct {
Id int
Name string
}
func (t *User) String() string {
str := fmt.Sprintf("id:%d, name:%s\n", t.Id, t.Name)
return str
}
func main() {
u := User{1, "alice"}
fmt.Println(&u)
}
方法與函數(shù)
方法和函數(shù)的區(qū)別
| 區(qū)別 | 函數(shù) | 方法 |
|---|---|---|
| 調(diào)用方式 | 函數(shù)名(實參列表) | 變量.方法名(實參列表) |
| 接收值類型時 | 不能將指針類型的數(shù)據(jù)直接傳遞 | 可直接使用指針類型的變量調(diào)用方法 |
type User struct {
Id int
Name string
}
func (t *User) Print() {
fmt.Printf("id:%d, name:%s\n", t.Id, t.Name)
}
func main() {
u := User{1, "alice"}
u.Print()
(&u).Print()
}
注意:從形式上看(&u)是傳入地址,但本質(zhì)仍然是值拷貝。
type User struct {
Id int
Name string
}
func (t User) Print() {
t.Id = 2
fmt.Printf("id:%d, name:%s\n", t.Id, t.Name)
}
func main() {
u := User{1, "alice"}
u.Print() // id:2, name:alice
(&u).Print() // id:2, name:alice
fmt.Printf("id:%d, name:%s\n", u.Id, u.Name) // id:1, name:alice
}