前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >GO 的方法集

GO 的方法集

作者头像
烟草的香味
发布于 2020-07-20 13:58:25
发布于 2020-07-20 13:58:25
53400
代码可运行
举报
文章被收录于专栏:烟草的香味烟草的香味
运行总次数:0
代码可运行

前言

之前在写 GOdemo 的时候, 写了这么一段程序(大概意思):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

type Test struct {
}

func (test *Test) print()  {
 println("test fun")
}

func main() {
 Test{}.print()
}

结果一编译就报错了: cannot call pointer method on Test literal

差不多意思是不能调用指针方法. 我一看, 确实, print方法声明的是指针类型. 这么说我就懂了, 加个取址就 OK 了吧? (&Test{}).print() 这样就可以调用了.

分析

由此大胆的假设, GO在将方法绑定到结构体的时候, 根据接收的结构体类型不同(值或指针), 会将方法绑定到不同的类型变量上, 也就是说, 指针类型只能调用指针类型的方法, 值类型只能调用值类型的方法.

验证一下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

type Test struct {
}

func (test *Test) print()  {
 println("test fun")
}

func (test Test) print2()  {
 println("test fun 2")
}

func main() {
 // 指针类型调用值类型方法
 (&Test{}).print2()
 // 指针类型调用指针类型方法
 (&Test{}).print()
 // 值类型调用值类型方法
 Test{}.print2()
 // 值类型调用指针类型方法
 Test{}.print()
}

结果如何? 只有在使用值类型调用指针类型方法时, 编译会报错, 其他情况都 OK.

假设推翻, GO方法的绑定规则应该是(网上搜了搜, 发现这玩意叫 GO 的方法集):

  1. 指针类型拥有 值/指针 的方法
  2. 值类型只拥有值类型的方法

那么问题来了, 我平常写的时候, 是这样的, 就不会报错呀, 怎么今天突然报错了? 他们有什么区别么?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
t := Test{}
t.print()

我十分确定, t变量不是指针, 但他就可以调用呀. 查了查发现, 是GO在编译的时候帮我们隐式的做了取址的操作. 那为什么这里可以帮忙, 上面就不行了呢? 搞不懂.

在查的时候, 还看到了大概这样的代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

// 定义个测试接口
type ITest interface {
 print()
}

type Test struct {
}

// 实现接口的类
func (test *Test) print()  {
 println("test fun")
}

func main() {
 ReceiveTest(Test{})
}

// 接收接口的方法
func ReceiveTest(t ITest)  {
 t.print()
}

这个时候, 向方法传值就会报错, 有了上面的经验, 我已经知道了, 值类型没有绑定print方法, 所以改成传递指针就可以了.而且, 在这里, 如果在 ReceiveTest方法中做取址的操作, 也么的用, 只能在向方法传参的时候做取值操作.

这里再假设一下, 方法在传参的时候是传递的复制值, 当对值进行复制传进函数的时候, 俨然已经不是原始的值了, 而是原始值的一个副本, 而对副本再进行取址, 已经是一个新地址了, 自然就没有绑定其指针函数. 而当参数是指针类型的时候, 对指针类型复制并传递, 方法接收到的是一个地址值, 虽然此地址值是一个副本, 但是指向的仍然是原对象.

OK, 验证假设(为了保证编译顺利, 只保留了基本内容):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import "fmt"

type Test struct {
 Name int
}

func main() {
 t := Test{}
 fmt.Printf("%p\n", &t)
 ReceiveTest(t)
}

func ReceiveTest(t Test)  {
 fmt.Printf("%p\n", &t)
}

打印结果不同, 果然不是同一个对象, 而是复制的一个副本. 而对于指针传递:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import "fmt"

type Test struct {
 Name int
}

func main() {
 t := &Test{}
 fmt.Printf("原始指针变量的地址: %p\n", &t)
 fmt.Printf("原始指针变量的值: %p\n", t)
 ReceiveTest(t)
}

// 接收接口的方法
func ReceiveTest(t *Test)  {
 fmt.Printf("接收指针变量的地址: %p\n", &t)
 fmt.Printf("接收指针变量的值: %p\n", t)
}

打印结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
原始指针变量的地址: 0xc00000e028
原始指针变量的值: 0xc000016068
接收指针变量的地址: 0xc00000e038
接收指针变量的值: 0xc000016068

结果发现, 指针传递保存的对象地址确实会原封不动的传递, 但是, 其指针变量却会创建副本传进来. 所以可以这样理解, 不管你是指针类型还是值类型, GO 在函数传参的时候, 都会对该内容创建一个副本进行传递.

那也就意味着, 如果传的是一个较大的对象, 进行值的传递, 会将整个对象全拷贝一份, 然后传递过去, 而传递指针只需要拷贝8字节的指针数据就可以了,

不过如果传入了指针类型, 就要直面在方法内部可能会对对象进行修改的风险.


至此, 最开始的疑问已经解答了, 被GO这个t.print(), 调用方法时的隐式转址蒙蔽了我的双眼... 虽然这样在使用的时候就不用特意区分变量类型是值还是地址, 但是有的地方帮我转了, 有的地方又不管我了, 感觉怪怪的. 再习惯习惯.

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-07-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 烟草的香味 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
Mac的JDK和Jenv(JAVA_HOME管理器)的详细配置使用教程
从Windows转为Mac的用户,第一次配置JDK环境变量可能有些不知所措;上次给搭建介绍了如何在Linux上配置JDK,这次给大家介绍怎么在Mac上配置JDK。配置好JDK,就可以运行Minecraft服务器或者是Apache Tomcat服务器等基于Java虚拟机的应用程序。
Mintimate
2021/02/01
14.9K1
Mac的JDK和Jenv(JAVA_HOME管理器)的详细配置使用教程
hadoop 2.6全分布安装
这一步完成后,最好重启一次系统,以便生效。然后可以用ping master(或slave01、slave02)试下,正常的话,应该能ping通
菩提树下的杨过
2018/09/20
5150
Cygwin本地安装版
cygwin本地安装版离线即可安装,使用十分方便,适合linux、安卓平台软件开发与测试时使用,倍受行业人员和学者们的青睐.
云深无际
2020/08/12
3.4K0
Cygwin本地安装版
搭建Hadoop集群
搭建集群作为一件事,应该一气呵成,希望你腾出一两个小时的时间来完成搭建,提前祝你搭建成功!
用户9615083
2022/12/25
3.2K0
搭建Hadoop集群
NB: JAVA_HOME should point to a JDK not a JRE
在Centos 6.10上部署项目前,使用yum安装jdk,配置环境变量,java -version正常输出,java -jar xx.jar能正常运行Spring Boot项目。但安装Maven并配置后报错。
geekfly
2022/04/24
4K0
NB: JAVA_HOME should point to a JDK not a JRE
Hadoop-2.4.1完全分布式环境搭建
一、配置步骤如下: 1.主机环境搭建,这里是使用了5台虚拟机,在Ubuntu 13系统上进行搭建Hadoop环境。 2.创建hadoop用户组以及hadoop用户,并给hadoop用户分配权限。 3.免密码登陆,为5台主机进行免密码登陆配置。 4.安装hadoop以及jdk,并配置环境变量。 5.Hadoop分布式环境参数配置。
星哥玩云
2022/07/04
2240
Spark伪分布式集群搭建
---- 软件准备 一台Linux虚拟机 我用的CentOS-6.6的一个虚拟机,主机名为repo 参考在Windows中安装一台Linux虚拟机 spark安装包 下载地址:https://mirrors.aliyun.com/apache/spark/ 我用的spark-2.2.0-bin-hadoop2.7.tgz 要根据自己机器中的hadoop版本选择对应的spark版本 ---- (1) 把安装包上传到服务器并解压 [root@repo soft]# tar -zxvf spark-2
CoderJed
2018/09/13
1.6K0
Spark伪分布式集群搭建
hadoop 3.2.0 环境搭建---------->入门一 配置环境
这里我用的是linux cent os7.5 虚拟机镜像 第一步:搭建linux虚拟机之前博客中有这里不详细介绍了 虚拟机搭建教程:https://my.osc
用户5899361
2020/12/07
5640
hadoop 3.2.0  环境搭建---------->入门一  配置环境
Hadoop学习笔记—22.Hadoop2.x环境搭建与配置
自从2015年花了2个多月时间把Hadoop1.x的学习教程学习了一遍,对Hadoop这个神奇的小象有了一个初步的了解,还对每次学习的内容进行了总结,也形成了我的一个博文系列《Hadoop学习笔记系列》。其实,早在2014年Hadoop2.x版本就已经开始流行了起来,并且已经成为了现在的主流。当然,还有一些非离线计算的框架如实时计算框架Storm,近实时计算框架Spark等等。相信了解Hadoop2.x的童鞋都应该知道2.x相较于1.x版本的更新应该不是一丁半点,最显著的体现在两点:
Edison Zhou
2018/08/20
8110
Hadoop学习笔记—22.Hadoop2.x环境搭建与配置
Hadoop分布式部署
对于Hadoop Master(ResourceManager/NameNode)节点硬件配置要高一些
用户5252199
2022/04/18
4930
Hadoop分布式部署
hadoop + docker 搭建hadoop学习环境
在学习大数据的情况下免不了自己搭建一个hadoop环境,但是使用虚拟机在自己的电脑上启动一个集群环境会很吃机器的资源,所以我们使用docker来进行搭建大数据的集群环境。同时docker搭建hadoop环境可以省去很多重复的步骤。
Tim在路上
2020/08/05
2K0
学习大数据环境搭建
安装虚拟机,IP地址192.168.52.129、主机名称centos、内存4G、硬盘50G
陶然同学
2023/02/24
8220
学习大数据环境搭建
JavaSE学习总结(一)——Java基础
本文介绍了Java编程语言的历史、特点、开发环境、开发工具、JDK的下载与安装、Java SE和Java EE的区别、Java 8的新特性、Java的应用场景、发展趋势以及Java相关的开源项目。
张果
2018/01/04
1.7K0
JavaSE学习总结(一)——Java基础
hadoop_学习_02_Hadoop环境搭建(单机)
官方版本:http://archive.apache.org/dist/hadoop/
shirayner
2018/08/10
7520
hadoop_学习_02_Hadoop环境搭建(单机)
kylin_异常_02_java.lang.NoClassDefFoundError: org/apache/hadoop/hive/conf/HiveConf 解决办法
ERROR [http-bio-7070-exec-10] controller.TableController:189 : org/apache/hadoop/hive/conf/HiveConf java.lang.NoClassDefFoundError: org/apache/hadoop/hive/conf/HiveConf
shirayner
2018/08/10
2.8K0
kylin_异常_02_java.lang.NoClassDefFoundError: org/apache/hadoop/hive/conf/HiveConf 解决办法
hbase_学习_01_HBase环境搭建(单机)
本文承接上一篇:hadoop_学习_02_Hadoop环境搭建(单机)  ,主要是搭建HBase的单机环境
shirayner
2018/08/10
6911
hbase_学习_01_HBase环境搭建(单机)
Spark完全分布式集群搭建
比如分别把这两个文件重命名为start-spark-all.sh和stop-spark-all.sh 原因: 如果集群中也配置HADOOP_HOME,那么在HADOOP_HOME/sbin目录下也有start-all.sh和stop-all.sh这两个文件,当你执行这两个文件,系统不知道是操作hadoop集群还是spark集群。修改后就不会冲突了,当然,不修改的话,你需要进入它们的sbin目录下执行这些文件,这肯定就不会发生冲突了。我们配置SPARK_HOME主要也是为了执行其他spark命令方便。
CoderJed
2018/09/13
1.4K0
Spark完全分布式集群搭建
【快速入门大数据】Hadoop分布式集群搭建
修改hadoop配置文件 /root/software/hadoop-2.6.0-cdh5.7.0/etc/hadoop
瑞新
2021/12/06
2350
【快速入门大数据】Hadoop分布式集群搭建
Hadoop环境搭建及安装
2) Xshell(可选):用于在本地访问虚拟服务器,也可选择其他远程工具,如SecureCRT
数人之道
2022/01/07
2.6K0
Hadoop环境搭建及安装
windows下虚拟机配置spark集群最强攻略!
1、虚拟机安装 首先需要在windows上安装vmware和ubuntu虚拟机,这里就不多说了 vmware下载地址:直接百度搜索,使用百度提供的链接下载,这里附上一个破解码 5A02H-AU243-
石晓文
2018/04/11
1.9K0
windows下虚拟机配置spark集群最强攻略!
相关推荐
Mac的JDK和Jenv(JAVA_HOME管理器)的详细配置使用教程
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验