结构体声明

为了说明函数以及方法调用的过程,这里先定义一个struct,在下面的描述中会使用到它。

type Person struct {

Name string

Age uint16

}

普通函数中的参数传递

在Golang中,普通函数的行参如果是值类型,那么调用的实参也必须是实参,反之,如果函数行参是指针类型,那么传入的实参必须是地址。我们来看几个例子。

行参要求值传递

// 定义一个普通函数,要求值传递

func tell(person Person) {

fmt.Printf("Hi, my name's %v, I'm %v years old", person.Name, person.Age)

}

实参按照值的方式传递

// 调用函数,提供一个struct实例

person := Person{"Tom", 28}

tell(person) // Hi, my name's Tom, I'm 28 years old

我们可以看到,这种调用肯定是没有问题的,程序能够正常运行,当然这也是理所当然的

实参按照指针的方式传递

// 调用函数,提供一个struct实例的地址

person := Person{"Tom", 28}

tell(&person) // 编译错误:Cannot use '&person' (type *Person) as type Person

这会直接报编译错误,因为函数要求传入的是一个值,而函数调用给的却是一个地址,是不符合编译器要求的。

行参要求指针传递

这种情况,对于普通函数来讲,与上面的情形类似,即实参必须是地址,而不能是值。这里就不举例了。

方法中的参数传递

由上面我们可以看出,其实对于普通函数而言,参数的传递方式非常直接,而且容易理解。即,函数要求什么,调用的时候就给它什么。

但是对于方法调用来说,就会稍微复杂一些了(其实这种复杂性是为了给程序员提供方便,是不是感觉有点矛盾?哈哈)

对象是值的情况

首先,让我们把上面的函数改成一个方法,并且要求使用值对象的方式传递对象

func (person Person) tell() {

fmt.Printf("Hi, my name's %v, I'm %v years old", person.Name, person.Age)

}

按照我们对于普通函数的理解,调用该方法时,我们必须提供一个值对象,即

person := Person{"Tom", 28}

person.tell() // Hi, my name's Tom, I'm 28 years old

这种方式肯定工作,而且与普通函数的行为一致。但是,接下来,我要给该函数提供一个指针,我们来看

// 得到一个结构体指针

var person *Person = &Person{"Tom", 28}

person.tell() // Hi, my name's Tom, I'm 28 years old

从上面的运行结果,我们看到,这种调用也是被允许的,并没有报错。但是为什么?

这其实由于Go在编译的时候,会帮我们做一些事情,把代码转换成类似下面这个样子

(*person).tell()

即,会把指针类型先进行取值运算,然后再将其传递给方法。有了背后这一个转换,程序员不用在调用的时候先进行取值运算,再调用方法。从这个角度来讲,这种操作是不是给程序员提供了方便?

对象是指针的情况

类似的,如果方法要求传入的对象是指针类型,Go也允许我们传入值对象,Go在背后也是做了一个转换,即把传入的值,先进行地址运算,然后再将其传入方法中。下面详细描述一下。

假设我们的方法改成这样

// 该方法接收一个指针对象

func (person *Person) tell() {

fmt.Printf("Hi, my name's %v, I'm %v years old", person.Name, person.Age)

}

调用的时候,我们可以传入指针,也可以传入值。下面是传入值的情况

person := Person{"Tom", 28}

person.tell() // Hi, my name's Tom, I'm 28 years old

之所以这种调用没有报错,也是因为Go其实在编译的时候,进行了转换

(&person).tell()

在方法内修改对象的属性值,是否会影响原来的对象?

让我们来考虑一种情况,如果方法要求的对象是值对象,即

func (person Person) rename(newName string) {

person.Name = newName

}

而在调用这个方法的时候,调用的对象是个指针,那么下面的程序输出什么?

var person *Person = &Person{"Tom", 28}

person.rename("Jimmy")

person.tell()

答案是Hi, my name's Tom, I'm 28 years old。名字并没有改变,即,虽然我们传递了一个指针给rename方法,但是在rename方法里面对于person的修改,并没有反映到外部的person对象。也就是说,方法内的对象与方法外的对象之间是值拷贝。

接下来,我们再看另外一种情况,即,方法要求传入的对象是指针,但是调用的时候是在值对象上进行访问

func (person *Person) rename(newName string) {

person.Name = newName

}

person := Person{"Tom", 28}

person.rename("Jimmy")

person.tell()

输出的结果是Hi, my name's Jimmy, I'm 28 years old,也就是说名字改变了,即使我们在调用的时候传入的是值对象。

总结

如果方法要求的是值对象,那么无论调用的时候传递的是值还是指针,都是值拷贝

如果方法要求的是指针,那么无论调用的时候传递的是值还是指针,都是地址拷贝

背后的原理:go在编译的时候会根据方法定义的要求对传入的对象进行取值或取地址运算

有疑问加站长微信联系(非本文作者)

golang 函数传多个参数_关于Golang中方法参数的传递相关推荐

  1. eta 深度学习 参数_深度学习中的参数梯度推导(一)

    必备的数学知识 矩阵微分与求导 前言 深度学习向来被很多人认为是"黑盒",因为似乎很多人都不清楚深度学习的运作方式,本系列<深度学习中的数学>的连载文章主要目的就是向大 ...

  2. python hist 参数_关于python中plthist参数的使用详解

    {"moduleinfo":{"card_count":[{"count_phone":1,"count":1}],&q ...

  3. finereport报表设计中模板数据集的sql语句中if的用法_报表工具中动态参数的灵活运用...

    报表开发过程中,有的时候我们会觉得普通参数很难满足一些业务需求,比如第二个数据集要引用第一个数据集的结果进行计算,动态控制 SQL 的过滤条件,动态列等,如果您遇到了这种情况,可以尝试使用动态参数即 ...

  4. python @classmethod 和 @staticmethod区别,以及类中方法参数cls和self的区别

    一.@classmethod 和 @staticmethod 1.staticmethod 作用:让类中的方法变成一个普通函数(普通函数没有绑定在任何一个特定的类或者实例上.所以与不需要对象实例化就可 ...

  5. Java中方法参数的传递

    Java中方法参数的传递: 众所周知,Java语言中只有值传递,看起来很好理解的一句话,那么来看一个例子: 输出结果: 这是一个经典问题,我想说说自己的理解: 首先,变量sa和sb分别包含一个字符串对 ...

  6. numpy中方法参数axis取值理解

    numpy中方法参数axis取值理解 首先不要使用什么横纵轴去理解,因为时间长了就忘记了,而且如果a是一个三维数组就没法解释了. axis等于0时,在shape中表示的是二维数组.那么np.amin( ...

  7. golang 没有名字参数_在 Golang 中用名字调用函数

    上个星期,我写了篇<Function call by name in Golang>.由于是英文的,所以被人诟病(说谁,谁知道!).好吧,现在用中文重新写一遍. Golang 中的函数跟 ...

  8. python怎么理解函数的参数_理解Python中函数的参数

    定义函数的时候,我们把参数的名字和位置确定下来,函数的接口定义就完成了.对于函数的调用者来说,只需要知道如何传递正确的参数,以及函数将返回什么样的值就够了,函数内部的复杂逻辑被封装起来,调用者无需了解 ...

  9. python 实例方法调用时可以忽略第一个参数_盘点Python中易忽略的函数

    Python 内置函数 1.ord() 函数是 chr() 函数(对于8位的ASCII字符串)或 unichr() 函数(对于Unicode对象)的配对函数,它以一个字符(长度为1的字符串)作为参数, ...

  10. java对url参数编码_对URL中的参数编码和解码

    有时,我们希望点击页面中的链接跳转其他页面,并且以get的方式传递一些参数.如果不对这些参数编码,可能会造成一些问题: 1.  参数中的空格可能会让你无法打开页面 2.  参数中的&符号会影响 ...

最新文章

  1. 【ACM】杭电OJ 1004
  2. 微软提出CLIPBERT:通过稀疏采样的视频语言学习
  3. win 对比工具-Araxis Merge
  4. iOS开发多线程篇—线程安全
  5. python正规教育机构-Python培训机构多吗 选择Python培训这些你都知道吗
  6. Linux简单命令收录(cal,passwd,clear)【下】
  7. typora高亮_用Typora实现写作排版一体化
  8. elk替代_Go进阶45:Golang简洁的日志收集系统(替代ELKB)
  9. 非同质化代币(NFT)概述
  10. Firefox扩展IE Tab Plus内置功能导致浏览所有网页加载superfish.com脚本
  11. 【全国大学生IoT设计竞赛】安谋科技灵动赛题国赛一等奖分享:多足仿生机器人
  12. Android系统充电指示灯无响应
  13. 【找不到与请求 URI匹配的 HTTP 资源】(转)
  14. 日记侠:你真的想知道引流的方法吗?
  15. python+OpenCv笔记(八):图像噪声(椒盐噪声、高斯噪声)
  16. 也谈特征值和特征向量的几何意义
  17. 计算机部分应用显示模糊,电脑显示器局部模糊怎么办
  18. 咏春拳段位首次开考先考动作再考功力2008-11-13
  19. pdf转换成txt转换器在线转换
  20. html页面点击图片名称查看图片------图片预览插件viewer.js使用

热门文章

  1. 代理服务器Tengine的研究与测试
  2. Delphi利用Windows GDI实现文字倾斜
  3. TP类库解析和使用系列[Input类]
  4. CSDN登陆校验码模式识别程序
  5. java中412是什么错_HTTP 412 错误 – 先决条件失败 (Precondition failed)
  6. GET和POST请求到底有什么区别?
  7. 分数的拆分原理和方法_常见的节税原理你知道吗?
  8. c4d流体插件_(图文+视频)C4D野教程:TFD、XP和RF三大流体插件协作案例
  9. python获取文件名不含后缀名_大部分Python资料都没有说到的重点-用实战教你解决问题的思路...
  10. android 自定义菜单栏,GitHub - earthWo/AndroidBottomNavigation: android 底部菜单栏,自定义样式,自定义菜单数量,添加滚动动画和水波纹动画...