golang函数传参——值传递理解

这篇具有很好参考价值的文章主要介绍了golang函数传参——值传递理解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

做了五年的go开发,却并没有什么成长,都停留在了业务层面了。一直以为golang中函数传参,如果传的是引用类型,则是以引用传递,造成这样的误解,实在也不能怪我。我们来看一个例子,众所周知,slice是个引用类型,我们以slice为例。

package main
​
import "fmt"
​
func main() {
  strSlice := make([]string, 0,10)
  strSlice = append(strSlice, "初始值")
  //打印一下没有在函数内部修改的初始情况
  fmt.Println("strSlice:",strSlice,"strSlice地址:",&strSlice[0])
  //在函数内部修改初始slice内容,再打印
  change(strSlice)
  fmt.Println("strSlice:",strSlice,"strSlice地址:",&strSlice[0])
}
func change(str []string){
  fmt.Println("函数传参地址:",&str[0])
  str[0]="改掉这个内容"
}

猜猜,打印出来的会是什么结果?

golang函数传参——值传递理解,golang,开发语言,后端,值传递 

​不管你是怎么看,如果只有这么一个案例,就很容易产生误解。打印的函数参数的地址和外部slice的地址是一致,并且在函数体内修改的值的确影响了slice的值,由此现象很容易得出是引用传递

事实果真如此么?我们再来看一个案例。

package main
​
import "fmt"
​
func main() {
  strSlice := make([]string, 0,10)
  strSlice = append(strSlice, "初始值")
  //打印一下没有在函数内部修改的初始情况
  fmt.Println("strSlice:",strSlice,"strSlice地址:",&strSlice[0])
  //在函数内部修改初始slice内容,再打印
  change(strSlice)
  fmt.Println("strSlice:",strSlice,"strSlice地址:",&strSlice[0])
}
func change(str []string){
  fmt.Println("函数传参地址:",&str[0])
  str=append(str,"新增一个内容")
}

 如果是引用传递,那么经过change函数追加了值的strSlice应该是能打印出追加的值。好了,我们直接看结果。

golang函数传参——值传递理解,golang,开发语言,后端,值传递

结果,很是出乎我的意料之外啊,竟然不是像我上面猜想的那样。由此至少可以得出一个结论,golang中函数的参数传递不是引用传递。那么,也就是说即使参数是引用类型,也是值传递,既然是值传递,第一个案例作何理解呢?第二个案例又如何理解呢?

我们看一下slice的底层结构。

//go 1.20.3 path: /src/runtime/slice.go
type slice struct {
 array unsafe.Pointer
 len   int
 cap   int
}

 array 是一个指向底层数组的指针,这个数组存储着切片中的元素。len 表示切片的长度,即切片中元素的数量。cap 表示切片的容量,即切片底层数组中可用的元素数量。golang的函数传参都是值传递,即使传递的是引用类型,也是对应引用类型的地址拷贝。因此,第一个案例中,实际上是把指向底层数组的指针的地址拷贝生成一个副本传到了函数体中,所以,第一个案例中修改了0xc00006c0a0地址里的内容会引发外面的参数发生变化。这个我们可以做个案例测试一下。

package main
​
import "fmt"
​
func main() {
  strSlice := make([]string, 0,10)
  strSlice = append(strSlice, "初始值")
  //打印一下没有在函数内部修改的初始情况
  fmt.Println("strSlice:",strSlice,"strSlice地址:",&strSlice[0])
  //在函数内部修改初始slice内容,再打印
  change(strSlice)
  fmt.Println("strSlice:",strSlice,"strSlice地址:",&strSlice[0])
}
func change(str []string){
  fmt.Println("函数传参地址:",&str[0])
  for i:=0;i<10;i++{
    str = append(str, fmt.Sprint(i))
  }
  fmt.Println("扩容之后的地址:",&str[0])
  str[0]="改掉这个内容"
}

我们知道,当slice发生扩容,runtime会开辟一块新的内存地址把内容拷贝到新的地址指向的内存中,那么,我们可以测试一下,当slice发生扩容,再修改内容,就不会影响原来的参数。

golang函数传参——值传递理解,golang,开发语言,后端,值传递 

​实际结果,验证了我们的猜想,扩容之后,开辟新的内存地址来存放内容,因此,再修改这个参数也不会影响外部参数。

可是这个依然没有解除掉第二个案例——没有扩容时,函数内append之后外部参数打印结果和预期不符的疑惑。实际上并不矛盾,因为,slice结构中有一个变量len,这个表示slice中元素的数量,用大白话来理解就是可见的元素,传参的过程中,不仅拷贝了地址,还拷贝了len和cap,因此,虽然形参中的len发生了变化,但是并不影响实参的len。画个内存示意图来理解一下。

golang函数传参——值传递理解,golang,开发语言,后端,值传递

package main
​
import "fmt"
​
func main() {
  strSlice := make([]string, 0,10)
  strSlice = append(strSlice, "初始值")
  //打印一下没有在函数内部修改的初始情况
  fmt.Println("strSlice:",strSlice,"strSlice地址:",&strSlice[0],"len=",len(strSlice))
  //在函数内部修改初始slice内容,再打印
  change(strSlice)
  fmt.Println("strSlice:",strSlice,"strSlice地址:",&strSlice[0],"len=",len(strSlice))
}
func change(str []string){
  fmt.Println("函数传参地址:",&str[0])
  str=append(str,"新增一个内容")
  fmt.Println("形参str长度:",len(str))
}

 golang函数传参——值传递理解,golang,开发语言,后端,值传递

直接看结果,果然验证了我们上面的猜想。

至此,函数值传递的探究到此结束。

 文章来源地址https://www.toymoban.com/news/detail-626087.html

到了这里,关于golang函数传参——值传递理解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C语言】函数调用及创建,并将数组传参到函数

      🎥 岁月失语唯石能言的个人主页         🔥 个人栏专: 秒懂C语言 ⭐ 若在许我少年时,一两黄金一两风      目录 前言 一、函数的概念 二、库函数 2.1 标准库和头文件 2.2库函数的使用方法 2.2.1功能 2.2.2库函数的头文件 2.2.3例子 2.2.4库函数文档的一般格式 三、自定义

    2024年02月04日
    浏览(33)
  • python通过ctypes传参numpy给c语言函数

    gcc -o demo.so -std=c++11 -shared -fPIC demo.c  python3 main.py 概述: 示例实现了numpy数组加上100并通过另外的数组的指针获取返回值。主要过程是 numpy数组转换成c_void_p类型,然后传参给c语言函数,c语言函数中指针强转到需要的数据类型,然后再处理。这样即可改变numpy数组中的数值实

    2024年02月12日
    浏览(30)
  • c语言中为什么函数传参大多数用指针类型

    在C语言中,函数传参大多数使用指针类型的原因主要有两个: 允许在函数内部修改实参的值:C语言中的函数参数传递是按值传递的,即将实参值拷贝一份到形参中进行操作,对参的修改不会影响实参。而通过使用指类型参数,可以将实参的地址传递给函数,从而在函数内部

    2024年02月09日
    浏览(32)
  • 【c语言】函数的数据传递原理 | 数组传入函数方法

    创作不易,本篇文章如果帮助到了你,还请点赞支持一下♡𖥦)!!  主页专栏有更多知识,如有疑问欢迎大家指正讨论,共同进步! 给大家跳段街舞感谢支持!ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ    函数基本概念知识:函数的基本概念、含义、结构  

    2023年04月23日
    浏览(27)
  • R语言【技巧】——判断自定义函数的传参内容是否符合要求

    比如 对一个应该传入 数值型 ,数值为 0 或 1 的参数: 比如 对一个应该传入 字符型 ,字符串为 某个向量元素之一 的参数,类似于选项框:

    2024年01月23日
    浏览(32)
  • c语言,函数的址传递例子

    编码如下: #include stdio.h void swap(int* x,int* y ){ int tmp; tmp=*x; *x=*y; *y=tmp ; }; int main() { int a=4; int b=5; printf(\\\"befern\\\"); printf(\\\"a=%dn\\\",a); printf(\\\"b=%dn\\\",b); swap(a,b); printf(\\\"aftern\\\"); printf(\\\"a=%dn\\\",a); printf(\\\"b=%dn\\\",b); return 0; } 输出的结果: befer a=4 b=5 after a=5 b=4

    2024年02月06日
    浏览(31)
  • C语言如何传递参数到函数,并从函数中返回值?

    假设我们现在要写一个函数,名字叫做\\\"吃饭\\\"。这个函数的功能是传入参数\\\"食物\\\",然后从函数中返回一个值\\\"满足程度\\\"。我们来看看如何实现吧! 我们需要写一个函数原型,声明这个函数的存在和参数的类型。嗯,函数原型就像餐厅的菜单,告诉顾客有哪些选择和怎么点菜。

    2024年02月12日
    浏览(33)
  • C 语言函数完全指南:创建、调用、参数传递、返回值解析

    函数是一段代码块,只有在被调用时才会运行。 您可以将数据(称为参数)传递给函数。 函数用于执行某些操作,它们对于重用代码很重要:定义一次代码,并多次使用。 事实证明,您已经知道什么是函数了 例如, main() 是一个函数,用于执行代码, printf() 也是一个函数,

    2024年02月03日
    浏览(47)
  • Golang(Go语言)IP地址转换函数

    String形式的IP地址和Int类型互转函数 代码 输出如下:  

    2024年02月05日
    浏览(40)
  • [uniapp的页面传参]详细讲解uniapp中页面传参的传递方式和接受方式 使用案例 代码注释

    在uniapp中,页面传参是非常常见的需求。本文将详细讲解uniapp中页面传参的传递方式和接受方式,以及使用案例,同时附上代码注释。 1. URL传参 URL传参是一种比较简单的传递方式,它是通过URL地址来传递参数的。我们可以在URL地址后面加上参数,例如: 在接收页面中,我们

    2024年02月19日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包