Go Method

作者: JunChow520 | 来源:发表于2021-01-12 02:25 被阅读0次

    Go语言同时支持函数和方法,方法是包含接收器的函数,接收器可以是命名类型或结构体类型的值或指针。为特定类型定义的方法属于该类型的方法集。

    • 方法在接收者参数的帮助下,可访问接收者的属性。
    • 方法的接收者可以是结构体类型或非结构体类型。

    方法会在func关键字和方法名之间添加一个特殊的接收器类型,接收器可以是结构体或非结构体类型,接收器可以在方法内部被访问。

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

    类型T上所有方法的集合称之为类型T的方法集

    Go语言不是纯粹的面向对象的编程语言,Go语言不支持类。因此,基于类型的方法是一种实现和类相似行为的途径。

    Go语言中结构体像是类的一种简化形式,如果将结构体视为类,则类的方法就是作用在接收器上的函数。接收本身是某种类型的变量,因此方法是一种特殊类型的函数。

    Go语言支持方法,方法与函数相似,不同之处在于方法中会包含一个接收者参数。创建方法时,接收者和接收者类型必须出现在同一个包中,禁止创建方法时的接收者在其它包中已经被定义。

    接收器类型可以是任何类型,但接收器不能是接口类型,因为接口是一个抽象的定义,而方法却是具体的实现。另外,接收器不能是一个指针类型,但可以说任何其他运行类型的指针。

    虽然类型与方法使结构体等价于面向对象中的累,但Go语言中类型的代码和绑定在其上的方法的代码可以不用放置在一起,因此可以存在于不同的源文件中,唯一的要求是必须在同一个包中。

    方法VS函数

    方法和函数定义区别在于方法的实例可以接受参数,编译器以此确定方法所属的类型。其它语言中,尽管没有显式地定义但也会在调用时隐式地传递this实例参数。

    Go语言中函数是不属于任何结构体、类型的方法,函数是没有接收器的,而方法则是具有接收器的,因此方法要么属于一个结构体,要么属于一个新定义的类型。

    Go语言中相同名字的方法可以定义在不同的类型上,但相同名字的函数是不被允许的。

    由于方法本质上是函数,因此不允许方法重载,对于一个类型只能有一个给定名称的方法。若基于接收器的类型,则可以重载。具有相同名字的方法可以在不同的接收器类型上存在,比如同一个包中。

    面向对象语言中类拥有的方法表示类所具有的行为,在Go语言中方法也是如此,只是Go语言建立的接收器会强调方法的作用对象是接收器即类的实例,而函数是没有作用对象的。

    方法 函数
    包含接收器 不包含接收器
    可接受指针和值 禁止同时接受指针和值
    可定义同名非同类型的方法 禁止定义同名非同类型的函数

    接收器

    方法的接收器支持值接收器和指针接收器,二者的区别在于指针接收器方法内部的改变对于调用者是可见的,值接收器则不可见。

    func (接收器变量 接收器类型) 方法名(参数列表) (返回参数) {
      方法体
    }
    
    • 接收器变量
      接收器中的参数变量命名时,官方建议使用接收器类型名称的首字母的小写,而非self、this之类的命名。
    • 接收器类型
      接收器类型和参数类似,可以是指针类型或非指针类型
    • 方法名、参数列表、返回值参数与函数定义相同

    Go语言中允许定义接收者为结构体类型的方法,方法内部可访问接收器字段。

    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语言中只要类型和方法定义在同一个包中,即可使用非结构体类型接收器创建方法。若存在intstring等不同的包中,则编译器会抛出错误。

    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语言中允许使用指针接收器创建方法,在指针接收器的作用下,对方法中所做的更改将反映到调用方中。

    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() {
        //初始化结构体
        user := User{Id:1, Name:"admin"}
        //创建指针
        ptr := &user
        //使用指针调用方法
        ptr.SetName("root")
        
        println(user.Name)//root
        println(ptr.Name)//root
    }
    

    方法可以接受指针和值

    Go语言中当一个函数具有值参数时仅会接受参数的值,若将指针传递给值函数则不会被接受,反之亦然。但Go语言的方法可以接受值和指针,无论是使用指针还是值接收器定义的。

    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
    }
    

    值接收器

    当方法作用于非指针接收器时,Go语言会在代码运行时将接收器的值复制一份,在非指针接收器的方法中可以获取接收器的成员值,但修改后无效。

    当使用值接收器声明的方法,调用时会使用值的副本来执行,因此该类型的值并不会被改变。

    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
    }
    

    使用指针来调用使用值接收器声明的方法时,指针被解引为值的副本,因此原指针变量指向的值不会发生改变。

    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
    }
    

    指针接收器

    指针类型的接收器由结构体的指针组成,更接近于面向对象中的this或self。

    由于指针的特性,调用方法时,修改接收器指针的成员变量,在方法结束后修改都是有效i的。

    使用类型的指针调用指针接收器声明的方法时,该方法会共享指针指向的值,因此会改变指针指向的☞。

    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
    }
    

    适用类型的值调用指针接收器声明的方法时,该方法会共享所指向的值,此时会改变指针指向的值。

    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
    }
    

    相关文章

      网友评论

          本文标题:Go Method

          本文链接:https://www.haomeiwen.com/subject/gndraktx.html