Go Method

Go語(yǔ)言同時(shí)支持函數(shù)和方法,方法是包含接收器的函數(shù),接收器可以是命名類型或結(jié)構(gòu)體類型的值或指針。為特定類型定義的方法屬于該類型的方法集。

  • 方法在接收者參數(shù)的幫助下,可訪問接收者的屬性。
  • 方法的接收者可以是結(jié)構(gòu)體類型或非結(jié)構(gòu)體類型。

方法會(huì)在func關(guān)鍵字和方法名之間添加一個(gè)特殊的接收器類型,接收器可以是結(jié)構(gòu)體或非結(jié)構(gòu)體類型,接收器可以在方法內(nèi)部被訪問。

func (receiver_name T)method_name(parameter_list) (return_type){

}

類型T上所有方法的集合稱之為類型T的方法集

Go語(yǔ)言不是純粹的面向?qū)ο蟮木幊陶Z(yǔ)言,Go語(yǔ)言不支持類。因此,基于類型的方法是一種實(shí)現(xiàn)和類相似行為的途徑。

Go語(yǔ)言中結(jié)構(gòu)體像是類的一種簡(jiǎn)化形式,如果將結(jié)構(gòu)體視為類,則類的方法就是作用在接收器上的函數(shù)。接收本身是某種類型的變量,因此方法是一種特殊類型的函數(shù)。

Go語(yǔ)言支持方法,方法與函數(shù)相似,不同之處在于方法中會(huì)包含一個(gè)接收者參數(shù)。創(chuàng)建方法時(shí),接收者和接收者類型必須出現(xiàn)在同一個(gè)包中,禁止創(chuàng)建方法時(shí)的接收者在其它包中已經(jīng)被定義。

接收器類型可以是任何類型,但接收器不能是接口類型,因?yàn)榻涌谑且粋€(gè)抽象的定義,而方法卻是具體的實(shí)現(xiàn)。另外,接收器不能是一個(gè)指針類型,但可以說任何其他運(yùn)行類型的指針。

雖然類型與方法使結(jié)構(gòu)體等價(jià)于面向?qū)ο笾械睦郏獹o語(yǔ)言中類型的代碼和綁定在其上的方法的代碼可以不用放置在一起,因此可以存在于不同的源文件中,唯一的要求是必須在同一個(gè)包中。

方法VS函數(shù)

方法和函數(shù)定義區(qū)別在于方法的實(shí)例可以接受參數(shù),編譯器以此確定方法所屬的類型。其它語(yǔ)言中,盡管沒有顯式地定義但也會(huì)在調(diào)用時(shí)隱式地傳遞this實(shí)例參數(shù)。

Go語(yǔ)言中函數(shù)是不屬于任何結(jié)構(gòu)體、類型的方法,函數(shù)是沒有接收器的,而方法則是具有接收器的,因此方法要么屬于一個(gè)結(jié)構(gòu)體,要么屬于一個(gè)新定義的類型。

Go語(yǔ)言中相同名字的方法可以定義在不同的類型上,但相同名字的函數(shù)是不被允許的。

由于方法本質(zhì)上是函數(shù),因此不允許方法重載,對(duì)于一個(gè)類型只能有一個(gè)給定名稱的方法。若基于接收器的類型,則可以重載。具有相同名字的方法可以在不同的接收器類型上存在,比如同一個(gè)包中。

面向?qū)ο笳Z(yǔ)言中類擁有的方法表示類所具有的行為,在Go語(yǔ)言中方法也是如此,只是Go語(yǔ)言建立的接收器會(huì)強(qiáng)調(diào)方法的作用對(duì)象是接收器即類的實(shí)例,而函數(shù)是沒有作用對(duì)象的。

方法 函數(shù)
包含接收器 不包含接收器
可接受指針和值 禁止同時(shí)接受指針和值
可定義同名非同類型的方法 禁止定義同名非同類型的函數(shù)

接收器

方法的接收器支持值接收器和指針接收器,二者的區(qū)別在于指針接收器方法內(nèi)部的改變對(duì)于調(diào)用者是可見的,值接收器則不可見。

func (接收器變量 接收器類型) 方法名(參數(shù)列表) (返回參數(shù)) {
  方法體
}
  • 接收器變量
    接收器中的參數(shù)變量命名時(shí),官方建議使用接收器類型名稱的首字母的小寫,而非self、this之類的命名。
  • 接收器類型
    接收器類型和參數(shù)類似,可以是指針類型或非指針類型
  • 方法名、參數(shù)列表、返回值參數(shù)與函數(shù)定義相同

Go語(yǔ)言中允許定義接收者為結(jié)構(gòu)體類型的方法,方法內(nèi)部可訪問接收器字段。

package main

type User struct {
    Name string
    Salary int
}

func (receiver User) test() {
    println(receiver.Name)
}

func main() {
    user := User{Name:"admin", Salary: 1000}
    user.test()
}

Go語(yǔ)言中只要類型和方法定義在同一個(gè)包中,即可使用非結(jié)構(gòu)體類型接收器創(chuàng)建方法。若存在int、string等不同的包中,則編譯器會(huì)拋出錯(cuò)誤。

package main

type integer int

func (receiver integer) add(value integer) integer{
    return receiver + value
}

func main() {
    v1 := integer(1)
    v2 := integer(2)
    result := v1.add(v2)
    println(result)//3
}

Go語(yǔ)言中允許使用指針接收器創(chuàng)建方法,在指針接收器的作用下,對(duì)方法中所做的更改將反映到調(diào)用方中。

func  (ptr *Type) method_name(...Type) Type {

}
package main

type User struct {
    Id int
    Name string
}
//使用User類型的接收者
func (this *User) SetName(name string){
    (*this).Name = name
}

func main() {
    //初始化結(jié)構(gòu)體
    user := User{Id:1, Name:"admin"}
    //創(chuàng)建指針
    ptr := &user
    //使用指針調(diào)用方法
    ptr.SetName("root")
    
    println(user.Name)//root
    println(ptr.Name)//root
}

方法可以接受指針和值

Go語(yǔ)言中當(dāng)一個(gè)函數(shù)具有值參數(shù)時(shí)僅會(huì)接受參數(shù)的值,若將指針傳遞給值函數(shù)則不會(huì)被接受,反之亦然。但Go語(yǔ)言的方法可以接受值和指針,無論是使用指針還是值接收器定義的。

package main

type User struct {
    Id int
    Name string
}
//帶指針的方法
func (this *User) SetName(name string){
    (*this).Name = name
}
//帶值得方法
func (this User) GetName(){
    println(this.Name)
}

func main() {
    //初始化值
    user := User{Id:1, Name:"admin"}
    user.SetName("root")
    user.GetName()//root
    (&user).GetName()//root
}

值接收器

當(dāng)方法作用于非指針接收器時(shí),Go語(yǔ)言會(huì)在代碼運(yùn)行時(shí)將接收器的值復(fù)制一份,在非指針接收器的方法中可以獲取接收器的成員值,但修改后無效。

當(dāng)使用值接收器聲明的方法,調(diào)用時(shí)會(huì)使用值的副本來執(zhí)行,因此該類型的值并不會(huì)被改變。

package main

import "fmt"

type User struct {
    Id int
    Name string
}
func (this User) SetName(name string){
    this.Name = name
}
func (this User) print(){
    fmt.Printf("id = %v, name = %v\n", this.Id, this.Name)
}

func main() {
    user := User{Id:1, Name:"admin"}
    user.SetName("root")
    user.print()//id = 1, name = admin
}

使用指針來調(diào)用使用值接收器聲明的方法時(shí),指針被解引為值的副本,因此原指針變量指向的值不會(huì)發(fā)生改變。

package main

import "fmt"

type User struct {
    Id int
    Name string
}
func (this User) SetName(name string){
    this.Name = name
}
func (this User) print(){
    fmt.Printf("id = %v, name = %v\n", this.Id, this.Name)
}

func main() {
    user := &User{Id:1, Name:"admin"}
    user.SetName("root")
    user.print()//id = 1, name = admin
}

指針接收器

指針類型的接收器由結(jié)構(gòu)體的指針組成,更接近于面向?qū)ο笾械膖his或self。

由于指針的特性,調(diào)用方法時(shí),修改接收器指針的成員變量,在方法結(jié)束后修改都是有效i的。

使用類型的指針調(diào)用指針接收器聲明的方法時(shí),該方法會(huì)共享指針指向的值,因此會(huì)改變指針指向的?。

package main

import "fmt"

type User struct {
    Id int
    Name string
}
func (this *User) SetName(name string){
    this.Name = name
}
func (this User) print(){
    fmt.Printf("id = %v, name = %v\n", this.Id, this.Name)
}

func main() {
    user := &User{Id:1, Name:"admin"}
    user.SetName("root")
    user.print()//id = 1, name = root
}

適用類型的值調(diào)用指針接收器聲明的方法時(shí),該方法會(huì)共享所指向的值,此時(shí)會(huì)改變指針指向的值。

package main

import "fmt"

type User struct {
    Id int
    Name string
}
func (this *User) SetName(name string){
    this.Name = name
}
func (this User) print(){
    fmt.Printf("id = %v, name = %v\n", this.Id, this.Name)
}

func main() {
    user := User{Id:1, Name:"admin"}
    user.SetName("root")
    user.print()//id = 1, name = root
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容