Go参数传递

在面试中,经常会被问起,这门语言的参数传递是值传递还是引用传递,当然,大部分情况下我们都会提前准备,有恃无恐,但还是希望能够精益求精嘛,所以针对Go语言来分析,Go传参是值传递还是引用传递。那首先,我们先来了解什么是值传递,什么是引用传递。

值传递

值传递就是函数传递的是传进来参数的一个副本。换个说法就是函数内部修改传入参数的值是函数外部传入值得一个拷贝,所以你在函数内部对这个值进行修改也不会影响外部该参数的值,的确很难表达,看个案例:

package main

import "fmt"

func modify(a int){
a = 10
} func main(){
a := 20
fmt.Println(a)
modify(a)
fmt.Println(a)
}

输出:

20
20

很直观,参数a在进入函数后并没有被改变,我们还可以看看两个内存地址是否相同

package main

import "fmt"

func modify(a int){
fmt.Println(&a)
a = 10
} func main(){
a := 20
fmt.Println(&a)
modify(a)
}

输出为:

0xc000052080
0xc000052088

可以看到两个内存地址并不一样,这就对了,可以说明modify中的参数a,并不是主函数中的变量a,而是a的一个拷贝而已,所以在函数中修改的也是拷贝a的值,对函数外的这个a并没有改动。

这个时候,我们就会使用指针来修改值,指针案例:

func main() {
i:=10
ip:=&i
fmt.Printf("原始指针的内存地址是:%p\n",&ip)
modify(ip)
fmt.Println("int值被修改了,新值为:",i)
} func modify(ip *int){
fmt.Printf("函数里接收到的指针的内存地址是:%p\n",&ip)
*ip=1
}

输出:

原始指针的内存地址是:0xc000006028
函数里接收到的指针的内存地址是:0xc000006038
int值被修改了,新值为: 1

可以看到两次内存地址也是不一样的,所以其实指针也是值传递,但是指针保存的是内存地址,而在函数中修改语句"*ip=1",其实是在修改变量i内存地址对应的值,那自然就是能够修改的。

引用传递

Go语言其实并没有引用传递,上面的例子可以证明如果内存地址不同自然就是值传递,那内存地址相同就是引用传递。

我们再通过Map类型进行验证,Map类型可以通过函数修改内容,但是他没有明显的指针。

func modify(p map[string]int){
fmt.Printf("函数里接收到map的内存地址是:%p\n",&p)
p["张三"] = 20
} func main(){
person := make(map[string]int)
person["张三"] = 56
fmt.Printf("原始map的内存地址是:%p\n",mp)
modify(person)
fmt.Println("map值被修改了,新值为:",person)
}

输出:

原始map的内存地址是:0xc00007e018
函数里接收到map的内存地址是:0xc00007e028
map值被修改了,新值为: map[张三:20]

发现两个内存地址是不一样的,所以这又是一个值传递,那为什么没有使用指针却修改了Map的内容?

查看一下map源码

func makemap(t *rtype, cap int) (m unsafe.Pointer)

我们发现这个方法返回的是m unsafe.Pointer继续查看一下unsafe.Pointer类型是什么?

type Pointer *ArbitraryType

返回的还是一个指针,所以我们可以得出map的传递也是值传递。

结论

确认Go语言中所有的传参都是值传递。但是传递的类型如果是int、string、struct等这些,那在函数中无法修改原参数内容数据;如果是指针、map、slice、chan等这些,在函数中可以修改原参数内容数据。

Go 参数传递的更多相关文章

  1. js学习之函数的参数传递

    我们都知道在 ECMAScript 中,数据类型分为原始类型(又称值类型/基本类型)和引用类型(又称对象类型):这里我将按照这两种类型分别对函数进行传参,看一下到底发生了什么. 参数的理解 首先,我们 ...

  2. kettle中含有参数传递的定时任务

    (1)新建一个作业(新建->作业),并在控制面板右键: (2)设置一个命令参数: (3)把作业的参数传递给转换: (4)在转换中右键设置转换属性: (5)接收作业中设置的传递参数: (6)参数的 ...

  3. Java基础知识笔记(七:接口、变量作用域和参数传递)

    一.接口 Java语言不允许一个子类拥有多个直接父类,即任何子类只能有一个直接父类.但允许一个类实现多个接口,即在定义类的接口名称列表中可以包含1个或多个接口名称,从而实现多重继承的特性.接口的定义格 ...

  4. shell 脚本之获取命令输出字符串以及函数参数传递

    在ubuntu 14.04之后,所有的U盘挂载也分用户之分,最近很多操作也和U盘有关,所以就研究了一上午shell脚本函数以及字符串操作的方法. 字符串操作: 获取他的命令输出比较简单,打个简单的比方 ...

  5. 【GoLang】golang 闭包 closure 参数传递的蹊跷!

    结论: 闭包函数可以直接引用外层代码定义的变量, 但是,注意,闭包函数里面引用的是变量的地址, 当goroutine被调度时,改地址的值才会被传递给goroutine 函数. 介绍 go的闭包是一个很 ...

  6. JQuery Mobile 页面参数传递

    在单页模版中使用基于HTTP的方式通过POST和GET请求传递参数,而在多页模版中不需要与服务器进行通信,通常在多页模版中有以下三种方法来实现页面间的参数传递. 1.GET方式:在前一个页面生成参数并 ...

  7. Java 中的值传递和参数传递

    Java中没有指针,所以也没有引用传递了,仅仅有值传递不过可以通过对象的方式来实现引用传递 类似java没有多继承 但可以用多次implements 接口实现多继承的功能 值传递:方法调用时,实际参数 ...

  8. 【Python学习】函数参数传递方法四种(位置,关键字,默认值,包裹位置,包裹关键字传递)

    1. 位置传递: #--coding:utf-8-- def send(name,address): return 'package is sent to %s, located in %s' %(n ...

  9. JAVA反射参数传递

    引用:http://fish2700.blog.163.com/blog/static/130713192009103035723281/ 使用Method反射调用函数时,我们通常会遇到以下几种情况: ...

  10. [蟒蛇菜谱]Python函数参数传递最佳实践

    将函数作为参数传递,同时将该函数需要的参数一起传递.可参考threading.Timer的处理方式: class threading.Timer(interval, function, args=[] ...

随机推荐

  1. Day17:web前端开发面试题

    1.JavaScript 数据类型有哪些? JavaScript 变量能够保存多种数据类型:数值.字符串值.数组.对象等等: var length = 7; // 数字 var lastName = ...

  2. 「ZJOI2019」麻将

    传送门 Solution  对于条件一:记录一个\(cnt\)表示牌个数\(≥2\)的个数 设\(dp_{i,0/1,j,k}\)表示考虑了\(1...i\),当前是否有对子,以\(i-1\),\(i ...

  3. [内网渗透]Windows中的用户帐户与组账户

    0x01 用户帐户 1.1 简介        用户帐户是对计算机用户身份的标识,本地用户帐户.密码存在本地计算机上,只对本机有效,存储在本地安全帐户数据库 SAM 中.        文件路径:C: ...

  4. Tcl二进制数据

    binary format 格式化描述符 参数1 参数2...参数N binary scan 二进制数据 格式化描述符 变量1 变量2 ... 变量N 格式化描述符由两部分组成,第一是格式化类型关键字 ...

  5. ldap和phpldapadmin的安装部署

    LDAP 安装 一.安装LDAP 1. 安装包 yum install openssl-devel gcc libtool-ltdl-devel -y yum install openldap-ser ...

  6. PHP cURL 超时设置 CURLOPT_CONNECTTIMEOUT 和 CURLOPT_TIMEOUT 的区别

    PHP cURL 的超时设置有两个 CURLOPT_CONNECTTIMEOUT 和 CURLOPT_TIMEOUT,他们的区别是: CURLOPT_CONNECTTIMEOUT 用来告诉 PHP 在 ...

  7. C# TcpListener TcpClient

    C# TcpListener TcpClient 使用,新建从控制台项目,引用System.Net 代码如下: using System; using System.Collections.Gener ...

  8. 【深入学习linux】系统分区与格式化

    分区:把大硬盘分为小的逻辑分区 格式化:写入文件系统 分区设备文件名:给每个分区定义设备文件名 挂载:给每个分区分配挂载点 分区->格式化->取名->分配挂载点(WINDOW下的盘弧 ...

  9. 初探Android逆向:通过游戏APP破解引发的安全思考

    如今移动互联网已经完全融入到我们的生活中,各类APP也是层出不穷,因此对于安卓APP安全的研究也尤为重要.本文通过对一款安卓APP的破解实例,来引出对于APP安全的探讨.(本人纯小白,初次接触安卓逆向 ...

  10. Sword libcurl库CURLE_COULDNT_CONNECT错误

    CURL: CURLE_COULDNT_CONNECT问题分析 测试环境描述在使用libcurl写http客户端进行压力测试的时候会遇到curl_easy_perform()返回CURLE_COULD ...