Golang中接收者方法语法糖的使用方法详解

作者:人艰不拆_zmc 时间:2024-05-21 10:26:49 

1、概述

在《Golang常用语法糖》这篇博文中我们讲解Golang中常用的12种语法糖,在本文我们主要讲解下接收者方法语法糖。

在介绍Golang接收者方法语法糖前,先简单说下Go 语言的指针 (Pointer),大致上理解如下:

  • 变量名前的 & 符号,是取变量的内存地址,不是取值;

  • 数据类型前的 * 符号,代表要储存的是对应数据类型的内存地址,不是存值;

  • 变量名前的 * 符号,代表从内存地址中取值 (Dereferencing)。

注意 1:golang 指针详细介绍请参见《Golang指针隐式间接引用》此篇博文。

2、接收者方法语法糖

在 Go 中,对于自定义类型 T,为它定义方法时,其接收者可以是类型 T 本身,也可能是 T 类型的指针 *T。

type Instance struct{}

func (ins *Instance) Foo() string {
return ""
}

在上例中,我们定义了 Instance 的 Foo 方法时,其接收者是一个指针类型(*Instance)。

func main() {
var _ = Instance{}.Foo() //编译错误:cannot call pointer method on Instance{} ,变量是不可变的(该变量没有地址,不能对其进行寻址操作)
}

因此,如果我们用 Instance 类型本身 Instance{} 值去调用 Foo 方法,将会得到以上错误。

type Instance struct{}

func (ins Instance) Foo() string {
return ""
}

func main() {
var _ = Instance{}.Foo() // 编译通过
}

此时,如果我们将 Foo 方法的接收者改为 Instance 类型,就没有问题。

这说明,定义类型 T 的函数方法时,其接收者类型决定了之后什么样的类型对象能去调用该函数方法。但,实际上真的是这样吗?

type Instance struct{}

func (ins *Instance) String() string {
return ""
}

func main() {
var ins Instance
_ = ins.String() // 编译器会自动获取 ins 的地址并将其转换为指向 Instance 类型的指针_ = (&ins).String()
}

实际上,即使是我们在实现 Foo 方法时的接收者是指针类型,上面 ins 调用的使用依然没有问题。

Ins 值属于 Instance 类型,而非 *Instance,却能调用 Foo 方法,这是为什么呢?这其实就是 Go 编译器提供的语法糖!

当一个变量可变时(也就是说,该变量是一个具有地址的变量,我们可以对其进行寻址操作),我们对类型 T 的变量直接调用 *T 方法是合法的,因为 Go 编译器隐式地获取了它的地址。变量可变意味着变量可寻址,因此,上文提到的 Instance{}.Foo() 会得到编译错误,就在于 Instance{} 值不能寻址。

注意 1:在 Go 中,即使变量没有被显式初始化,编译器仍会为其分配内存空间,因此变量仍然具有内存地址。不过,由于变量没有被初始化,它们在分配后仅被赋予其类型的默认零值,而不是初始值。当然,这些默认值也是存储在变量分配的内存空间中的。

例如,下面的代码定义了一个整型变量 x,它没有被显式初始化,但是在分配内存时仍然具有一个地址:

var x int
fmt.Printf("%p\n", &x) // 输出变量 x 的内存地址

输出结果类似于:0xc0000120a0,表明变量 x 的内存地址已经被分配了。但是由于变量没有被初始化,x 的值将为整型的默认值 0。

3、深入测试

3.1 示例

package main

type B struct {
   Id int
}

func New() B {
   return B{}
}

func New2() *B {
   return &B{}
}

func (b *B) Hello() {
   return
}

func (b B) World() {
   return
}

func main() {
   // 方法的 * 为 *T 类型
   New().Hello() // 编译不通过

b1 := New()
   b1.Hello() // 编译通过

b2 := B{}
   b2.Hello() // 编译通过

(B{}).Hello() // 编译不通过
   B{}.Hello()   // 编译不通过

New2().Hello() // 编译通过

b3 := New2()
   b3.Hello() // 编译通过

b4 := &B{} // 编译通过
   b4.Hello() // 编译通过

(&B{}).Hello() // 编译通过

// 方法的 * 为 T 类型
   New().World() // 编译通过

b5 := New()
   b5.World() // 编译通过

b6 := B{}
   b6.World() // 编译通过

(B{}).World() // 编译通过
   B{}.World()   // 编译通过

New2().World() // 编译通过

b7 := New2()
   b7.World() // 编译通过

b8 := &B{} // 编译通过
   b8.World() // 编译通过

(&B{}).World() // 编译通过
}

输出结果:

./main.go:25:10: cannot call pointer method on New()
./main.go:25:10: cannot take the address of New()
./main.go:33:10: cannot call pointer method on B literal
./main.go:33:10: cannot take the address of B literal
./main.go:34:8: cannot call pointer method on B literal
./main.go:34:8: cannot take the address of B literal

3.2 问题总结

假设 T 类型的方法上 * 既有 T 类型的,又有 *T 指针类型的,那么就不可以在不能寻址的 T 值上调用 *T * 的方法

  • &B{} 是指针,可寻址

  • B{} 是值,不可寻址

  • b := B{} b是变量,可寻址

4、总结 

在 Golang 中,当一个变量是可变的(也就是说,该变量是一个具有地址的变量,我们可以对其进行寻址操作),我们可以通过对该变量的指针进行方法调用来执行对该变量的操作,否则就会导致编译错误。

来源:https://www.cnblogs.com/zhangmingcheng/p/17395367.html

标签:Go,语法糖
0
投稿

猜你喜欢

  • python import 引用上上上级包的三种方法

    2021-09-22 12:56:38
  • 区别JavaScript函数声明与变量声明

    2024-04-18 09:34:42
  • 网页设计五原则

    2007-11-03 13:50:00
  • python 基于Apscheduler实现定时任务

    2022-03-29 00:53:32
  • Python合并字典键值并去除重复元素的实例

    2022-02-10 17:48:40
  • 详解Selenium+PhantomJS+python简单实现爬虫的功能

    2023-03-09 01:09:00
  • Python Pygame实战之塔防游戏的实现

    2021-12-15 08:57:22
  • 女神相册密码忘记了 我只用Python写了20行代码

    2021-05-01 13:27:11
  • js键盘事件全面控制

    2008-02-21 12:51:00
  • 详解python Todo清单实战

    2021-11-03 06:24:50
  • Script 元素 type 属性的妙用

    2011-03-07 16:13:00
  • tensorflow建立一个简单的神经网络的方法

    2022-09-27 17:01:51
  • Python爬虫模拟登录带验证码网站

    2022-02-18 21:33:48
  • .NET中IoC框架Autofac用法讲解

    2024-06-05 09:26:21
  • mysql属于关系型数据库吗

    2024-01-23 03:11:30
  • Python用20行代码实现完整邮件功能

    2023-04-06 12:20:49
  • 基于PHP选项与信息函数的使用详解

    2024-05-13 09:23:34
  • ASP中类的详细介绍(class Property Get、Property Let)

    2008-02-20 19:18:00
  • pandas 数据归一化以及行删除例程的方法

    2022-05-23 09:11:23
  • python学习之whl文件解释与安装详解

    2021-11-01 18:09:14
  • asp之家 网络编程 m.aspxhome.com