2023-11-09(go方法)

2023-11-08  本文已影响0人  护念

今日概述

最近几天没来写日志,有点懈怠,今天开始总结下go的方法知识点。

1. 方法和函数的区别

  1. 方法有一个接收者对象(定义时显示写出来)
  2. 对于方法而言,值/指针调用编译器会自动转换成接收者的类型可以混用;但是函数不行—关键点。

比如:

package main

import "fmt"

type Person struct {
    name string
    age  int
}

// 值接收者
func (p Person) Hello() {
    fmt.Println("Hello")
}

// 指针接收者
func (p *Person) Welcome() {
    fmt.Println("welcome")
}

// 函数 这个时候只能输入 值
func FunHello(name string) {
    fmt.Println(name)
}

func main() {
    p := Person{"张数", 12}

    // 值/指针都可以调用
    p.Hello()
    (&p).Hello()

    p.Welcome()
    (&p).Welcome()

    name := "dmy"
    FunHello(name)
    //FunHello(&name) cannot use &name (value of type *string) as string value in argument to FunHello
}

2. 结构体匿名字段-结构体方法提升

在上述情况下,字段结构体的方法会提升到当前结构体可用。

package main

import "fmt"

type Human struct {
    work string
}

func (h *Human) WorkInfo() {
    fmt.Printf("work info: %v\n", h.work)
}

type Person struct {
    name  string
    age   int
    Human // 等同于字段名也是 Human Human的方法会提升
}

func (p *Person) Name() {
    fmt.Printf("My name: %v\n", p.name)
}

func main() {
    p := Person{
        name:  "张三",
        age:   12,
        Human: Human{work: "cleaner"}, // 虽然混合这里要分开写
    }

    // 此时person同时有了Person和Human的方法
    p.Name()
    p.WorkInfo()
}

3. 表达式

我的简单理解是,它可以用于将方法暂时不执行,留着后续执行;
它有两种:

  1. 方法值(这种封装了方法对象在里面)
  2. 方法表达式值(这种没有封装对象,执行是需要传参进入)
package main

import "fmt"

type Person struct {
    name string
    age  int
}

func (p *Person) Name() {
    fmt.Printf("My name: %v\n", p.name)
}

func (p Person) Age() {
    fmt.Printf("My age: %v\n", p.age)
}

func main() {
    p := Person{
        name: "张三",
        age:  12,
    }

    // 方法值表达式
    Val := p.Name
    Val() // 内部封装了对象p

    // 方法表达式
    exp := Person.Age
    exp(p) // 内部没有封装对象p所以要传
}

另外一点区别是,对于表达式,如果是指针接收者,则写的时候必须严格按照指针写。

举例说明:

package main

import "fmt"

type Person struct {
    name string
    age  int
}

func (p *Person) Name() {
    fmt.Printf("My name: %v\n", p.name)
}

func (p Person) Age() {
    fmt.Printf("My age: %v\n", p.age)
}

func main() {
    p := Person{
        name: "张三",
        age:  12,
    }

    // 方法表达式 - 此时写随便写都行
    exp := Person.Age
    exp(p) // 内部没有封装对象p所以要传

    // 这里改成指针 也没问题
    exp1 := (*Person).Age
    exp1(&p)

    // 如果是指针类型则只能指针
    exp2 := (*Person).Name
    exp2(&p)

    // 报错
    // exp3 := Person.Name
    // exp3(p) // invalid method expression Person.Name (needs pointer receiver (*Person).Name)
}

4. 一点特别的说明

  1. nil可以转换成指针类型
  2. 但是nil 不能转换成值类型
package main

type Data struct{}

func (Data) TestValue() {}

func (*Data) TestPointer() {}

func main() {
    var p *Data = nil
    p.TestPointer()

    // 这里是将 nil 转换成 *Data类型
    (*Data)(nil).TestPointer() // method value
    (*Data).TestPointer(nil)   // method expression

    // p.TestValue()            // invalid memory address or nil pointer dereference

    // (Data)(nil).TestValue()  // cannot convert nil to type Data
    // Data.TestValue(nil)      // cannot use nil as type Data in function argument
}
上一篇 下一篇

猜你喜欢

热点阅读