1. 前言

在Go语言中,函数和方法是不太一样的,函数是指不属于任何结构体、类型的方法,也就是说函数是没有接收者的; 而方法是有接收者的,要么是属于一个结构体的,要么属于一个新定义的类型的。

2. 方法和接收

在 Go 语言中,结构体就像是类的一种简化形式,Go的方法(Method)是一种作用于特定类型变量的函数。 这种特定类型变量叫做接收者(Receiver)。


// 接收者的类型可以是任何类型
// type ReceiverType int

type ReceiverType struct {
}

 func (接收者变量 ReceiverType) 方法名(参数列表) (返回参数) {
        函数体
    }
  • 参数和返回值可以省略

  • 接收者变量:接收者中的参数变量名在命名时,官方建议使用接收者类型名的第一个小写字母。

  • 接收者类型:接收者类型和参数类似,可以是指针类型和非指针类型。

  • 方法名、参数列表、返回参数:具体格式与函数定义相同。

package main

import "fmt"

type Person struct {
    Name  string
    Age     int
    Address string
}

// Person的方法
func (p Person) PrintPerson() {
    fmt.Printf(p.Name)
}

// NewPerson构造函数
func NewPerson(name string) *Person {
    return &Person{
        Name: name,
    }
}

func main() {
    NewPerson("雨中笑").PrintPerson()  // 输出:雨中笑
}

3. 值类型的接收者

当方法作用于值类型接收者时,go语言会在代码运行时将接收者的值复制一份。在值类型接收者的方法中可以获取接收者的成员值,但修改操作只是针对副本,无法修改接收者变量本身。

package main

import "fmt"

type Person struct {
    Name  string
    Age     int
    Address string
}

// NewPerson构造函数
func NewPerson(name string) *Person {
    return &Person{
        Name: name,
    }
}

// 使用值接收者
func (p Person) SetName(name string) {
    p.Name = name
}

func main() {
    p := NewPerson("雨中笑")
    fmt.Println(p.Name) // 雨中笑
    p.SetName("你好")
    fmt.Println(p.Name) // 雨中笑
}

4. 指针类型的接收者

指针类型的接收者由一个结构体的指针组成,在调用方法时修改接收者指针的任意成员变量,在方法结束后,修改都是有效的。

package main

import "fmt"

type Person struct {
    Name  string
    Age     int
    Address string
}

// NewPerson构造函数
func NewPerson(name string) *Person {
    return &Person{
        Name: name,
    }
}

// 使用指针接收者
func (p *Person) SetName(name string) {
    p.Name = name
}

func main() {
    p := NewPerson("雨中笑")
    fmt.Println(p.Name) // 雨中笑
    p.SetName("你好")
    fmt.Println(p.Name) // 你好
}

对于什么时候使用指针类型接收者,我们可以根据:

  • 需要修改接收者中的值

  • 接收者是拷贝代价比较大的对象

  • 保证一致性,如果有某个方法使用了指针接收者,那么其他的方法也应该使用指针接收者。

5. 接收者为值类型、指针类型的变量互调方法

接收者为指针类型时,可以直接用值类型的变量调用方法,接收者为值类型时,可以直接用指针类型的变量调用方法。

package main

import "fmt"

type Person struct {
    Name  string
    Age     int
    Address string
}

// 使用值类型接收者
func (p Person) Value() {
    fmt.Printf("我是值类型接收者:%s;Value: %p \n", p.Name, &p)
}

// 使用指针类型接收者
func (p *Person) Point() {
    fmt.Printf("我是指针类型接收者:%s;Point: %p \n\n", p.Name, p)
}

func main() {
    // 值类型调用
    pv := Person{"小明", 18, "广东"}
    fmt.Printf("我是数据测试者:%s;Person: %p \n", pv.Name, &pv)
    pv.Value()
    pv.Point()

    // 指针类型调用方法
    pp := &Person{"小红",18, "杭州"}
    fmt.Printf("我是数据测试者:%s;Person: %p \n", pp.Name, pp)
    pp.Value()
    pp.Point()
}

输出:

我是数据测试者:小明;Person: 0x11019a20 
我是值类型接收者:小明;Value: 0x11019a40 
我是指针类型接收者:小明;Point: 0x11019a20 

我是数据测试者:小红;Person: 0x11019a60 
我是值类型接收者:小红;Value: 0x11019a80 
我是指针类型接收者:小红;Point: 0x11019a60

6. 任意类型添加方法

在Go语言中,接收者的类型可以是任何类型(但不能给别的包的类型定义方法)。

package main

import "fmt"

//MyString 将string定义为自定义MyString类型
type MyString string

//Say 为MyString添加一个Say的方法
func (m MyString) Say() {
    fmt.Println("你好!")
}
func main() {
    var m MyString
    m.Say() //输出: 你好!。
    m = "雨中笑"
    fmt.Printf("%#v  %T\n", m, m) //输出:"雨中笑"  main.MyString
}

7. 对象的继承

go语言使用结构体实现其他编程语言中面向对象的继承。

package main

import "fmt"

type Person struct {
    Name  string
    Age     int
    Address string
}

type Student struct {
    Id int
    *Person
}

func (s *Student) Say() {
    fmt.Printf("Student-学生的id:%d\n", s.Id)
}

func (p *Person) Hello() {
    fmt.Printf("Person-学生的信息-姓名:%s\n", p.Name)
}

func main() {
    student := &Student{
        Id: 123,
        Person: &Person{
            Name: "小明",
            Age: 18,
            Address: "广东",
        },
    }

    student.Say()   //输出:Student-学生的id:123
    student.Hello() //输出:Person-学生的信息-姓名:小明
}
Copyright © yzx该文章修订时间: 2021-11-03 15:39:20

results matching ""

    No results matching ""