首页 > 其他分享 >没错,Go 语言的函数参数没有引用传递方式

没错,Go 语言的函数参数没有引用传递方式

时间:2024-10-25 18:59:53浏览次数:7  
标签:field six print 传递 函数参数 person func Go 没错

这篇文章想浅浅地讲解 Go 语言函数参数传递的值拷贝。

一句话观点

Go语言中所有传递都是值传递,严格来说并不存在引用传递的概念。传递指针只是传递指针的值,并不是引用传递,只不过通过指针可以间接修改变量的值,从而达到类似引用传递的效果。

值传递

值传递就是将参数的副本传递给函数,因此在函数内部修改参数的值,不会影响到原始变量的值。

  
func modifyValue(person Person) {  
    person.Name = "Alice"  
}

func Test4(t *testing.T) {  
    person1 := Person{Name: "Bob"}  
    modifyValue(person1)  
    fmt.Println("值传递:", person1.Name) // 输出: 值传递: Bob
}

在这个例子中,modifyValue 函数接收 person 的副本,修改它的字段值并不会影响原来的 person

引用传递

要实现引用传递,可以通过传递指针来实现。

func modifyReference(person *Person) {  
    person.Name = "Alice"  
}

func Test4(t *testing.T) {  
	person2 := &Person{Name: "Bob"}  
	modifyReference(person2)  
	fmt.Println("引用传递:", person2.Name) // 输出: 引用传递: Alice
}

在这个例子中,modifyReference 函数接收的是 person 指针类型的副本,修改副本指向的值,会影响到原来的。

值传递例子

下面再看一个值传递的例子。恰好最近在读《Go 语言精进之路》这本书,书里有一段讲解的方法的本质问题,案例是下面这段代码:

type field struct{ name string }  
  
func (p *field) print() {  
    fmt.Println(p.name)  
}  
func main() {  
    data1 := []*field{{"one"}, {"two"}, {"three"}}  
    for _, v := range data1 {  
       go v.print()  
    }  
    data2 := []field{{"four"}, {"five"}, {"six"}}  
    for _, v := range data2 {  
       go v.print()  
    }  
    time.Sleep(3 * time.Second)  
}

我对上面的代码进行简单改造,改为单测方法,打印输出内存地址,改造的代码如下:

  
func (p *field) print() {  
    fmt.Printf("%p %s \n", p, p.name)  
}  
  
func Test1(t *testing.T) {  
    data1 := []*field{{"one"}, {"two"}, {"three"}}  
    for _, v := range data1 {  
       go (*field).print(v)  
    }  
    
    data2 := []field{{"four"}, {"five"}, {"six"}}  
    for _, v := range data2 {  
       go (*field).print(&v)  
    }  
    time.Sleep(3 * time.Second)  
}

运行单测,看下结果:

0xc000026590 six 
0xc000026590 six 
0xc000026590 six 
0xc000026540 two 
0xc000026530 one 
0xc000026550 three 

如果你奇怪为什么第二段代码输出的全是 six,那么可以接着看下面的原因分析。

先要知道的是, for range 循环中会重复使用同一个变量 v

在第一段,data1 是一个指针数组([]*field),v 每次迭代时是指向数组中不同元素的指针。由于 v 是指针,每个元素的地址自然是不同的,因此打印出的地址不同,每个元素都可以打印出来。

在第二段,data2 是一个结构体数组([]field),而 v 是数组元素的副本。当你取 &v 时,每次获取的都是这个循环中的同一个变量的地址,所以 &v 的地址是相同的。但每次迭代时,这个地址指向的值会被更新为 data2 中当前元素的副本,在最后执行的时候,&v 执行的值就是 six

如果想让第二段输出所有元素,可以每次迭代拷贝一个 v 副本,复制给变量 s,如下:

for _, v := range data2 {  
    s := v  
    go (*field).print(&s)  
}

执行单测,输出结果如下:

0xc0000265d0 six 
0xc000026590 four 
0xc0000265b0 five 
0xc000026540 two 
0xc000026550 three 
0xc000026530 one 

在这个例子中,每次迭代都会创建新的变量 s,内存地址是不同的,所以可以全部输出。

Over!

标签:field,six,print,传递,函数参数,person,func,Go,没错
From: https://www.cnblogs.com/denglei1024/p/18503128

相关文章

  • c++/python/java/go用途介绍
    C++用途:系统编程:操作系统、驱动程序等底层开发。游戏开发:游戏引擎和高性能游戏应用,因其高效的性能和内存管理。嵌入式系统:适合资源受限的设备。科学计算:高性能计算和数值分析。金融系统:高频交易和复杂金融模型。Python用途:数据科学与分析:广泛用于数据处理和可视化......
  • go 连MQ
    go连MQpackagemainimport( "context" "fmt" "os" "github.com/apache/rocketmq-client-go/v2" "github.com/apache/rocketmq-client-go/v2/primitive" "github.com/apache/rocketmq-client-go/v2/produce......
  • [转]阅读Go源码的顿悟时刻
    文章转自:https://zhuanlan.zhihu.com/p/2119163293我对各个顿悟时刻简单的总结如下:切片为什么切片操作后总返回一个新切片:因为其内部的数组会在容量满后自动扩容预先分配切片的大小避免扩容是个好办法协程是合作式的(cooperative)go中高效的GMP模型go的编......
  • go微服务介绍【负载均衡,主从数据库,微服务架构】【实现了:高并发,语言之间互通】
    1.go单体架构程序一天访问量5万以下没问题2.使用负载均衡:单体架构的程序部署在多台服务器,可实现每天几十万的访问量3.如果是几百万或上前万的访问量,数据库也需要扩展,用到主从数据库4.当每天有上亿访问量,或者更高并发量的时候,上面的方法就有点力不存心了,这个时候我们就可以使......
  • mongodb获取配置参数getParameter和setParameter设置参数
    1、获取某个配置参数的值:db.runCommand({getParameter:1,tcmallocAggressiveMemoryDecommit:1})2、设置某个配置参数的值:db.adminCommand({setParameter:1,tcmallocAggressiveMemoryDecommit:1})restcloud1:SECONDARY>db.runCommand({getParameter:1,tcmallocAggressiveM......
  • MongoDB配置文件详解--转
    一配置文件说明MongoDB有两种配置文件格式,分别是:3.2版官方yaml配置文件选项参考用=号的常规格式类似my.conf等常规配置的文件yaml语法的新格式mongodb3.x版本后就是要yaml语法格式的配置文件,下面是yaml配置文件格式如下:切记yaml只能使用空格,不支持tab键,切记配置举例配置......
  • Go语言的工具链介绍
    文章开头段落:Go语言的工具链介绍mAInly包括:1、编译和链接工具,比如gobuild和goinstall;2、包管理和版本控制工具,比如goget和gomod;3、代码格式化和优化工具,比如gofmt和govet;4、测试和分析工具,比如gotest和gobench。Go语言的开发工作流程非常致力于简洁和效率,所以集成了一......
  • Netty、Go、Apache Tomcat、grpc-go、jetty、nghttp2、Apache Traffic Server是什么
    这些都是与网络编程和服务器应用相关的技术,下面我将分别简要介绍它们:Netty:Netty是一个异步事件驱动的网络应用程序框架,用于快速开发高性能、高可靠性的网络服务器和客户端程序。它支持多种协议,包括HTTP、HTTPS、FTP、SMTP等,广泛应用于游戏、移动、物联网、大数据等领域。......
  • go_test2
    packagemainimport( "github.com/gin-gonic/gin" "html/template" "net/http" "time")typeAddressstruct{ Mobilestring Emailstring}typeNewsstruct{ Titlestring Contentstring}funcFormatUnix......
  • go_test1
    packagemainimport( "github.com/gin-gonic/gin" "net/http")typeArticlestruct{ Idint`json:"id"` Titlestring`json:"title"`}funcmain(){ //定义路由 r:=gin.Default() //返回字符串 r.GET("/&......