go 调用其他文件函数_一篇文章让你了解Go语言中方法Methods的使用内幕
概述
Go语言中的方法只不过是一个带有接收器的函数。接收器是某个特定类型(如struct)的实例,或是任何其他自定义类型的实例。所以基本上,当你把函数附加到类型上时,该函数就成为这个类型的一个方法。方法可以访问接收器的属性,并能调用接收器的其他方法。
为什么要使用方法
方法允许你在类型上定义函数,这项特性使你能够用Go语言编写面向对象的代码。还有其他的好处,比如在一个包中两个不同的方法可以具有相同的名字,而函数不可能这样做。
方法的格式
下面是定义一个方法常用的签名:
接收器receiver及其类型receiver_type出现在func关键字和函数名之间,返回值return_values放在最后。
方法和函数有些重要的区别,先看一下函数的签名
函数:
下面是方法的签名
方法:
从上面的签名可以看出,方法有一个receiver参数。这是函数和方法之间唯一的区别,正因于此,它们提供的功能不同:
- 函数可以用作一阶对象,作为参数传递给其它函数,而方法则不能。
- 方法在接收器可以链式调用,而函数不能。
- 不同的接收器可以拥有相同名字的不同方法,但同一包中不能存在两个相同名字的不同函数。
结构上的方法
Go语言不是面向对象的语言。它不支持类型继承,但它允许我们在任何自定义类型(包括结构)上定义方法。由于struct是字段的命名集合,因此也可以在其上定义方法。因此,Go语言中的结构struct可以和面向对象语言中的类class来做比较。
让我们看一个结构struct上的方法的示例:
注意,接收器在方法内部可用,接收器的字段可以在方法内部访问。
接收器的字段也可以在方法内修改吗?
让我们看看:
在上面的代码中,在employee结构上定义了一个方法setNewName。在这个方法中,我们更新员工的名字:
在设置了新名字后,当我们在main函数中再次打印员工姓名时,可以看到原来的名字Sam被打印出来,而不是John。这是因为方法是在值接收器上定义的。
因为方法是在一个值接收器上定义的,当方法被调用时,创建的是接收器的副本,是接收器的副本在方法内部可用。由于它是一个副本,对值接收器所做的任何修改对调用者都是不可见的。这就是为什么它打印旧名字Sam而不是John。现在的情形是,是否有方法可以解决这个问题。答案是肯定的,这就是使用指针接收器。
指针接收器上的方法
在上面的示例中,我们看到了一个值接收器上的方法。对值接收器所做的任何修改对调用方都不可见。方法也可以在指针接收器上定义,对指针接收器所做的任何修改都对调用者可见。让我们看一个例子:
上面的代码中,我们的方法setNewName定义在指针接收器上:
然后,创建了一个employee的指针并对其调用setNewName方法。可以看到在setNewName内部对指针接收器employee所做的修改对调用者是可见的,最后的结果打印出新的名字。
是否只能创建employee指针来调用带有指针接收器的方法?不,不是的。可以在employee实例上调用该方法,Go语言将其作为指针正确地传递给该方法,这种灵活性是由Go语言保证的。
让我们看一个例子:
我们在上面的程序中看到,即使在指针接收器上定义了一个方法,但我们使用非指针employee实例同样也能调用该方法。
Go语言将实例接收器作为指针传递,因此调用者可以看到方法内部修改的结果。
下面的调用方式也是合法的:
现在,换个角度来考察。如果方法是在值接收器上定义的,可以用指针接收器调用该方法吗?
是的,这也是合法的,Go语言会将参数作为值接收器正确传递,而不管此方法是在指针还是在普通结构实例上调用。
让我们看一个例子:
请注意,在上面代码中的三种情况,由于setNewName方法定义在值接收器上,因此调用方无法看到更改,因为接收器是作为副本传递的,这三种情况下都打印旧名。
总结一下我们目前所学到的:
- 如果方法有值接收器,它支持用值接收器和指针接收器调用该方法。
- 如果方法有指针接收器,那么它也支持用值和指针接收器调用该方法。
这与函数不同
- 如果函数有指针参数,则它只接受指针作为参数传递。
- 如果函数有值参数,那么它只接受值作为参数传递。
何时使用指针接收器?
- 当方法内部对接收器所做的修改必须对调用方可见时。
- 当结构较大时,最好使用指针接收器,否则每次调用方法时都会生成一个结构副本,代价非常昂贵。
关于方法还有一些需要注意的地方:
- 接收器类型必须与方法在同一个包中定义,把方法定义在另一个包中的接收器上时,会引发以下错误:
ERROR: cannot define new methods on non-local types
- 到目前为止,我们已经看到使用点运算符来调用方法,除此之外,还有另一种方法可以调用方法,如下例所示:
在上面的例子中,我们看到了调用方法的不同方式,有两种情况
- 当方法有值接收器时,可以按如下方式调用它,即结构名后跟方法名,第一个参数是值接收器本身:
- 当方法有指针接收器时,它可以按如下方式调用,即结构名的指针后跟方法名,第一个参数是指针接收器:
另外请注意,对于上面的setName函数,该方法的参数从第二个参数开始:
这种方法调用方式很少被使用,点符号的调用方式是最常见的。
匿名嵌套结构字段上的方法
让我们看一个程序:
注意在上面的程序中,结构address的details方法可以通过两种方式访问:
如上所示,对于匿名嵌套结构,可以直接访问该结构的方法。
导出方法
Go语言没有任何public、private或protected关键字,控制包外部可见性的唯一机制是使用大小写格式。
- 大写标识符的首字母是导出:首字母大写表示这是一个导出的标识符,可以在包外使用。
- 小写标识符的首字母是不导出:首字母小写表示标识符不导出,只从同一个包中访问。
因此,任何以大写字母开头的结构都会导出到其他包中。类似地,任何以大写字母开头的结构的字段也会导出,首字母小写则不导出。同样,任何以大写字母开头的结构的方法也会被导出。让我们看一个示例,它显示了导出和不导出结构、结构字段和方法。查看下面model.go以及test.go的代码,两者都属于main包。
结构
- Person结构是导出的
- company结构是不导出的
结构的字段
- Person结构的Name字段是导出的
- Person结构的age字段是不导出的但Name字段是导出的
结构的方法
- Person结构的GetAge方法是导出的
- Person结构的getName方法是不导出的
下面是model.go的代码:
下面是test.go的代码:
运行test.go文件时,它可以访问与它同包的model.go中的所有导出和未导出字段,因为两者都在同一个包中。没有编译错误,输出正常。
但是,如果我们移动文件model.go到另一个名为model的包,运行go build的输出将给出编译错误,所有的编译错误都是因为test.go在主包中不能引用model包中model.go结构未导出的字段。
编译错误将是:
方法涟
要使方法链接成为可能,链中的每个方法应该返回接收器,链中最后一个方法的接收器是可选的。
让我们看一个方法链接的例子。
非结构类型上的方法
方法也可以在非结构自定义类型上定义。可以通过类型定义创建非结构自定义类型。下面是创建新自定义类型的格式:
例如,我们可以使用float64类型的命名自定义类型myFloat:
方法可以在命名的自定义类型上定义,参见以下示例:
结论
这就是Go语言中关于方法使用的所有内幕,希望你喜欢这篇文章,请在评论中分享反馈关注!
go 调用其他文件函数_一篇文章让你了解Go语言中方法Methods的使用内幕相关推荐
- go 调用其他文件函数_一文读懂Go中软件包概念
Go编程语言的软件包管理和部署的完整概述 如果您熟悉Java或NodeJS之类的语言,那么您可能非常熟悉软件包. 包不过是带有一些代码文件的目录,该目录从单个引用点公开了不同的变量(功能). 让我解释 ...
- go 调用其他文件函数_【C# 调用 Go 语言】0x1 Hello Golang
C# 和 Golang 都不是世界上最好的语言.在不同的业务场景下,C# 和 Golang 各有所长.如果要编写一个网络程序,显然 Golang 更擅长,而如果要编写一个桌面 GUI 程序,那么 C# ...
- 有关python方面的论文_一篇文章可以带你理解python中的类
继续上一章的内容,上一章说到了python的核心部分-创建对象的各种名词的定义,包括:对象,类,多态,封装,继承,接口和内省,面向对象设计.还有不清楚的可以review一下前文.python核心部分创 ...
- mql 查询多结果_一篇文章带你全面掌握Excel中的各种数据查询知识与技巧
数据查询是Excel数据处理中的一项核心业务,也是日常办公中使用频率非常高的一项操作.数据查询业务需求多,而且具有较强的技巧性,因此它也是职场必学的一门技能. 本篇文章从最基本的数据查询的概念讲起,逐 ...
- java中抽象接口_一篇文章让你彻底理解java中抽象类和接口
相信大家都有这种感觉:抽象类与接口这两者有太多相似的地方,又有太多不同的地方.往往这二者可以让初学者摸不着头脑,无论是在实际编程的时候,还是在面试的时候,抽象类与接口都显得格外重要!希望看完这篇博客文 ...
- c枚举类型enum例题_一篇文章让你详细了解Java中Enum枚举类的使用
文章前记 程序员工作久了便可能整日忙碌于"增删改查"中,迷失方向,毫无进步. 该公众号致力于分享软件开发相关的原创干货,助你完成从程序员到架构师的进阶之路! 努力!做一个NB的Co ...
- matlab基于dct的图像压缩编码解码_一篇文章搞定DCT在JPEG中的本质
前序傅立叶变换,离散傅立叶变换,推荐这个回答的介绍 想和大家讨论一下jpeg中的dct变换,为什么有效?它有什么更深层次的本质吗?www.zhihu.com 全篇参考下文,英文较好可以直接看. uc ...
- python 不执行函数_解决python调用自己文件函数/执行函数找不到包问题
写python程序的时候很多人习惯创建一个utils.py文件,存放一些经常使用的函数,方便其他文件调用,同时也更好的管理一些通用函数,方便今后使用.或是两个文件之间的class或是函数调用情况. 就 ...
- 一篇文章帮你搞定JVM中的堆
文章目录 一篇文章帮你搞定JVM中的堆 堆的核心概述 堆的内存细分 设置堆内存大小与OOM OOM(OutOfMemory)举例 年轻代与老年代 图解对象分配过程 MinorGC,MajorGC,Fu ...
最新文章
- Jquery empty() remove() detach() 方法的区别
- PHP的ob多级缓冲设置
- Android 开发之多线程处理、Handler 详解
- 你不知道的JS(this)---#
- Apache kafka原理与特性(0.8V)
- 折线分割平面(HDU-2050)
- java mysql tomcat my_Java、Tomcat 及 MySQL 环境配置
- 蚂蚁金服一面二面试题及答案,职位Java高级工程师
- [Hadoop大数据]——Hive数据的导入导出
- 【车道线检测与寻迹】2月13日 CV导论+数字图像处理与opencv实践+canny边缘检测
- java面试基础_java面试之基础(总结)
- 浙江省高考计算机重点知识,2017届浙江省新高考信息技术考试标准
- 一个Java程序员对2011年的回顾
- 矩阵连乘(动态规划)
- hive删除EXTERNAL外表
- 语义分割中样本分布不均衡怎么办
- CTF基础知识与web信息泄露下的目录遍历、PHPINFO、备份文件下载
- html5开发战棋游戏,个人耗时三月独立开发的无限流战棋游戏求龙友们给些建议。 ......
- 02. Excel_数据处理_基本操作(2)
- 智能客服能用于哪些场景?
热门文章
- AQS及其组件的核心原理
- 面试官:分布式环境下,如何实现session共享
- 错误记录(一)Could not get constructor for org.hibernate.persister.entity.SingleTableEntityPersister报错解决办法
- fetch oracle 12c下载,十二、Oracle Fetch子句
- 【2019.09.14】2019icpc沈阳网络赛
- PAT-Travel Plan (30)-Dijkstra和SPFA
- 浅谈FFT(快速博立叶变换)学习笔记
- Python3基础3——List列表的增删改和内建函数的用法
- Springmvc+mybatis配置前台页面传递JSON串给后台接收。
- Ubuntu 创建快捷方式的方法