golang值接收者和指针接收者的区别介绍
作者:蔡蔡217 发布时间:2024-04-25 13:20:33
方法
方法能给用户自定义的类型添加新的行为。它和函数的区别在于方法有一个接收者,给一个函数添加一个接收者,那么它就变成了方法。接收者可以是值接收者,也可以是指针接收者。
在调用方法的时候,值类型既可以调用值接收者的方法,也可以调用指针接收者的方法;指针类型既可以调用指针接收者的方法,也可以调用值接收者的方法。
package main
import "fmt"
type Person struct {
age int
}
func (p Person) AddAge() {
p.age += 1
}
func (p *Person) GetAge() {
p.age += 1
}
func main() {
// p1 是值类型
p := Person{age: 18}
// 值类型 调用接收者也是值类型的方法
p.AddAge()
fmt.Println(p.age)
// ----------------------
// p2 是指针类型 指针类型调用接收者是值类型的方法
p2 := &Person{age: 100}
p2.AddAge()
fmt.Println(p2.age)
//值类型 调用接收者也是指针类型的方法
p3 := Person{age: 18}
p3.GetAge()
fmt.Println(p3.age)
// 指针类型 调用收者也是指针类型的方法
p4 := Person{age: 100}
p4.GetAge()
fmt.Println(p4.age)
}
//18
//100
//19
//101
值接收者 | 指针接收者 | |
---|---|---|
值类型调用者 | 传递一个副本 | 使用值的引用来调用方法 |
指针类型调用者 | 传递一个副本 | 方法里的操作会影响到调用者,类似于指针传参,拷贝了一份指针 |
总结:
1.一个结构体的方法的接收者可能是类型值或指针
2.当接受者不是一个指针时,该方法操作对应接受者的值的副本,即使你使用了指针调用函数,但是函数的接受者是值类型,所以函数内部操作还是对副本的操作,而不是指针操作。
3.如果接收者是指针,则调用者修改的是指针指向的值本身。
接口实现
当结构体实现一个接口时,可以在方法中设置一个接收者,比如对于以下接口:
type Inter interface {
foo()
}
结构体在实现它时,方法的接收者类型可以是:值、指针。比如:
type S struct {}
func (s S) foo() {} // 值类型
func (s *S) foo() {} // 或者指针类型
在使用结构体初始化接口变量时,结构体的类型也可以是:值、指针。比如:
//赋值
var s Inter = S{} // 值类型
s.foo()
var s Inter = &S{} // 指针类型
s.foo()
那么调用接口方法的组合实际有四种情况:
值类型结构体 -> 赋值给接口 -> 调用接收者类型为值类型的结构体方法
指针类型结构体 -> 赋值给接口 -> 调用接收者类型为指针类型的结构体方法
值类型结构体 -> 赋值给接口 -> 调用接收者类型为指针类型的结构体方法(不通过)
指针类型结构体 -> 赋值给接口 -> 调用接收者类型为值类型的结构体方法
结构体类型为值类型、调用了接收者为指针的方法不通过。但是反过来,结构体为指针类型时,却可以调用接收值为值或指针的任何方法。这是为什么呢?
接收者是方法的一个额外的参数,而 Go 在调用函数的时候,参数都是值传递的。将一个指针拷贝,它们还是指向同一个地址,指向一个确定的结构体;将一个值拷贝,它们变成了两个不同的结构体,有着不同的地址。这会导致以下两种情况:
当在一个结构体指针上,通过接口,调用一个接收者为值类型的方法时,Go 首先会创建这个指针的副本,然后将这个指针解引用,再作为接收者参数传递给该方法。这两个指针指向相同的地址,所以它们传递给方法的接收者参数都是相同的。
type Inter interface {
foo()
}
type S struct {}
func (s S) foo() {} // 接收者为值类型的方法
var a Inter = &S{} // 使用结构体指针初始化一个接口
a.foo() // 调用 foo 方法
// 实际上底层是这样的:
// 首先拷贝 a 的底层值,即 `&S{}`,是一个结构体指针:
var b *S = a.inner_value // a、b 是不同的变量,但是指向同一个结构体
// 然后将 b 解引用,传递给 foo:
foo(*b) // *b 和 *(a.inner_value) 其实都表示同一个结构体
这些规则用来说明是否我们一个类型的值或者指针实现了该接口:
类型 *T 的可调用方法集包含接受者为 *T 或 T 的所有方法集
类型 T 的可调用方法集包含接受者为 T 的所有方法
两者分别在何时使用
如果方法的接收者是值类型,无论调用者是对象还是对象指针,修改的都是对象的副本,不影响调用者;如果方法的接收者是指针类型,则调用者修改的是指针指向的对象本身。
使用指针作为方法的接收者的理由:
方法能够修改接收者指向的值。
避免在每次调用方法时复制该值,在值的类型为大型结构体时,这样做会更加高效。
是使用值接收者还是指针接收者,不是由该方法是否修改了调用者(也就是接收者)来决定,而是应该基于该类型的本质。
来源:https://blog.csdn.net/weixin_42128977/article/details/126511071


猜你喜欢
- 如何剔除HTML标识?这里没有使用正则表达式来去除,当然大家用正则"<.+?>"也可以实现这个功能只留下干净
- 看代码吧~# -*- coding:utf-8 -*- import osimport jsonimport numpy as np #fr
- 对str类型数据进行split操作如下:>>> s = 'abc\ndef'>>> s.
- 访问者模式我觉得Visitor模式是在补修改已有程序结构前提下,通过添加额外的访问者完成对代码功能的拓展 为什么这样用?当你的类层次较多,在
- 偶第一次发主题, 这个是在一个项目中的做...写的一般般, 有什么bug之类的是在所难免, 望见谅功能说明:1. 即时控制用户输入2. 将输
- 用 docx 模块读取 Worddocx 安装cmd 中输入pip install python-docx 即可安装 docx 模块docx
- --创建测试表 DECLARE @Users TABLE ( ID INT IDENTITY(1,1), UserInfo XML ) --
- 本文记录了mysql8.0.0 winx64.zip解压版安装教程,具体内容如下1、自己到mysql官网下载mysql-8.0.0-dmr-
- centos下安装配置phpmyadmin,我花了二个晚上,郁闷的我不行,配置phpmyadmin简单吧,很简单,我刚工作的时候,就配置过,
- 本文的爬虫教程分为四部: 1.从哪爬 where &nbs
- SQL JOIN 连接SQL JOIN 子句用于把来自两个或多个表的行结合起来,基于这些表之间的共同字段。最常见的 JOIN 类型:SQL
- 本文实例为大家分享了Python获取指定网页源码的具体代码,供大家参考,具体内容如下1、任务简介前段时间一直在学习Python基础知识,故未
- 本文实例讲述了Python实现提取XML内容并保存到Excel中的方法。分享给大家供大家参考,具体如下:最近做一个项目是解析XML文件,提取
- 先看一个示例代码如下<template> <div align="center" styl
- 前言本文给大家介绍的是关于在vue单页应用中使用jquery的相关内容,主要记录一个今天用到的vue-cli建立的应用中引入jquery的方
- 目录一.准备工作二.预览1.启动2.运行3.结果三.设计思路四.源代码4.1 GUI.py4.2 Search_Apps.py五.总结一.准
- 本文是一篇关于《Effective Python》书中一节的学习笔记,记录了示例代码和思路。如果函数要产生一系列结果,那么最简单的做法就是把
- 前言在pytorch中经常会遇到图像格式的转化,例如将PIL库读取出来的图片转化为Tensor,亦或者将Tensor转化为numpy格式的图
- 前言python中图像处理相关库有很多,这里简单介绍PIL、cv2、scipy.imageio 、matplotlib.image、skim
- 前言:为什么要写这篇文章,因为前段时间有一个开源的github中的项目有一个朋友提交了一个pr看了下是帮忙优化了下代码(十分感谢这位网友)。