概述

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的使用内幕相关推荐

  1. go 调用其他文件函数_一文读懂Go中软件包概念

    Go编程语言的软件包管理和部署的完整概述 如果您熟悉Java或NodeJS之类的语言,那么您可能非常熟悉软件包. 包不过是带有一些代码文件的目录,该目录从单个引用点公开了不同的变量(功能). 让我解释 ...

  2. go 调用其他文件函数_【C# 调用 Go 语言】0x1 Hello Golang

    C# 和 Golang 都不是世界上最好的语言.在不同的业务场景下,C# 和 Golang 各有所长.如果要编写一个网络程序,显然 Golang 更擅长,而如果要编写一个桌面 GUI 程序,那么 C# ...

  3. 有关python方面的论文_一篇文章可以带你理解python中的类

    继续上一章的内容,上一章说到了python的核心部分-创建对象的各种名词的定义,包括:对象,类,多态,封装,继承,接口和内省,面向对象设计.还有不清楚的可以review一下前文.python核心部分创 ...

  4. mql 查询多结果_一篇文章带你全面掌握Excel中的各种数据查询知识与技巧

    数据查询是Excel数据处理中的一项核心业务,也是日常办公中使用频率非常高的一项操作.数据查询业务需求多,而且具有较强的技巧性,因此它也是职场必学的一门技能. 本篇文章从最基本的数据查询的概念讲起,逐 ...

  5. java中抽象接口_一篇文章让你彻底理解java中抽象类和接口

    相信大家都有这种感觉:抽象类与接口这两者有太多相似的地方,又有太多不同的地方.往往这二者可以让初学者摸不着头脑,无论是在实际编程的时候,还是在面试的时候,抽象类与接口都显得格外重要!希望看完这篇博客文 ...

  6. c枚举类型enum例题_一篇文章让你详细了解Java中Enum枚举类的使用

    文章前记 程序员工作久了便可能整日忙碌于"增删改查"中,迷失方向,毫无进步. 该公众号致力于分享软件开发相关的原创干货,助你完成从程序员到架构师的进阶之路! 努力!做一个NB的Co ...

  7. matlab基于dct的图像压缩编码解码_一篇文章搞定DCT在JPEG中的本质

    前序傅立叶变换,离散傅立叶变换,推荐这个回答的介绍 想和大家讨论一下jpeg中的dct变换,为什么有效?它有什么更深层次的本质吗?​www.zhihu.com 全篇参考下文,英文较好可以直接看. uc ...

  8. python 不执行函数_解决python调用自己文件函数/执行函数找不到包问题

    写python程序的时候很多人习惯创建一个utils.py文件,存放一些经常使用的函数,方便其他文件调用,同时也更好的管理一些通用函数,方便今后使用.或是两个文件之间的class或是函数调用情况. 就 ...

  9. 一篇文章帮你搞定JVM中的堆

    文章目录 一篇文章帮你搞定JVM中的堆 堆的核心概述 堆的内存细分 设置堆内存大小与OOM OOM(OutOfMemory)举例 年轻代与老年代 图解对象分配过程 MinorGC,MajorGC,Fu ...

最新文章

  1. Jquery empty() remove() detach() 方法的区别
  2. PHP的ob多级缓冲设置
  3. Android 开发之多线程处理、Handler 详解
  4. 你不知道的JS(this)---#
  5. Apache kafka原理与特性(0.8V)
  6. 折线分割平面(HDU-2050)
  7. java mysql tomcat my_Java、Tomcat 及 MySQL 环境配置
  8. 蚂蚁金服一面二面试题及答案,职位Java高级工程师
  9. [Hadoop大数据]——Hive数据的导入导出
  10. 【车道线检测与寻迹】2月13日 CV导论+数字图像处理与opencv实践+canny边缘检测
  11. java面试基础_java面试之基础(总结)
  12. 浙江省高考计算机重点知识,2017届浙江省新高考信息技术考试标准
  13. 一个Java程序员对2011年的回顾
  14. 矩阵连乘(动态规划)
  15. hive删除EXTERNAL外表
  16. 语义分割中样本分布不均衡怎么办
  17. CTF基础知识与web信息泄露下的目录遍历、PHPINFO、备份文件下载
  18. html5开发战棋游戏,个人耗时三月独立开发的无限流战棋游戏求龙友们给些建议。 ......
  19. 02. Excel_数据处理_基本操作(2)
  20. 智能客服能用于哪些场景?

热门文章

  1. AQS及其组件的核心原理
  2. 面试官:分布式环境下,如何实现session共享
  3. 错误记录(一)Could not get constructor for org.hibernate.persister.entity.SingleTableEntityPersister报错解决办法
  4. fetch oracle 12c下载,十二、Oracle Fetch子句
  5. 【2019.09.14】2019icpc沈阳网络赛
  6. PAT-Travel Plan (30)-Dijkstra和SPFA
  7. 浅谈FFT(快速博立叶变换)学习笔记
  8. Python3基础3——List列表的增删改和内建函数的用法
  9. Springmvc+mybatis配置前台页面传递JSON串给后台接收。
  10. Ubuntu 创建快捷方式的方法