一文带你深入了解Golang中的参数传递机制

 更新时间:2024年01月14日 08:20:49   作者:路多辛  
值传递和引用传递是编程语言中两种主要的参数传递方式,决定了函数调用过程中实参如何影响形参以及函数内部对形参的修改是否会影响到原始实参,下面就跟随小编一起深入了解下golang中参数传递机制吧

值传递(Pass by Value)和引用传递(Pass by Reference)是编程语言中两种主要的参数传递方式,决定了函数调用过程中实参(实际参数)如何影响形参(形式参数)以及函数内部对形参的修改是否会影响到原始实参。

什么是值传递 (Pass by Value)

在值传递中,当函数被调用时,实参的值会被复制一份,并将这个副本传递给对应的形参,函数内部对形参的操作不会改变实参的原始值。

优点:

  • 安全,函数内对参数的修改不会影响原始数据。
  • 简单清晰好理解,函数可以随意操作参数而不会影响外部的值。

缺点:

创建副本可能导致额外的内存消耗,特别是当数据结构较大时。

不能直接修改原始数据,需要通过返回值或者使用指针/引用。

引用传递 (Pass by Reference)

在引用传递中,传递的是实参的内存地址,而不是实际值。因此,函数内部对形参的任何修改都会直接影响到原始实参的值。

优点:

  • 节省内存,因为没有创建实际数据的副本。
  • 在函数内可以直接修改原始数据。

缺点:

  • 安全性降低,因为函数内部的修改会影响到函数外部的原始数据。
  • 可能导致代码难以理解和维护,因为数据可以在多个地方被修改。

Golang 中的参数传递方式

在 Go 语言中,所有的函数参数传递都是值传递(pass by value),当将参数传递给函数时,实际上是将参数的副本传递给函数。然而,这并不意味着在函数内部对参数的修改都不会影响原始数据。因为在 Go 中,有些数据类型本身就是引用类型,比如切片(slice)、映射(map)、通道(channel)、接口(interface)和指针(pointer)。当这些类型作为参数传递给函数时,虽然传递的是值,但值本身就是一个引用。

基本类型的值传递

基本类型(如int、float、bool 和 string)的简单示例如下:

package main
 
import "fmt"
 
func modifyValue(x int) {
    x = 100
}
 
func main() {
    original := 1
    modifyValue(original)
    fmt.Println(original) // 输出 1,未被修改
}

在上面的例子中,original 是一个 int 类型的变量,当被传递到 modifyValue 函数时,实际上是传递了它的副本。因此,在函数内部对 x 的修改并不会影响 original 的值。

切片的“引用”传递

看一个切片的例子,来理解下虽然是值传递,但看起来像是引用传递的情况。简单示例代码如下:

package main
 
import "fmt"
 
func modifySlice(s []int) {
    s[0] = 100
}
 
func main() {
    originalSlice := []int{1, 2, 3}
    modifySlice(originalSlice)
    fmt.Println(originalSlice) // 输出 [100, 2, 3],第一个元素被修改
}

在这个例子中,尽管 originalSlice 作为一个值传递给了 modifySlice 函数,但是这个值实际上是一个切片的引用。切片内部包含一个指向数组的指针,因此在函数内部修改切片的元素,实际上是修改了这个内部数组,从而影响了原始的切片。

使用指针实现引用传递

现在看看如何使用指针来实现类似引用传递的效果,从而能够在函数内部修改基本类型的值。简单示例代码如下:

package main
 
import "fmt"
 
func modifyPointer(x *int) {
    *x = 100
}
 
func main() {
    original := 1
    modifyPointer(&original)
    fmt.Println(original) // 输出 100,被修改
}

在这个例子中,传递了 original 变量的地址给 modifyPointer 函数。因为传递的是一个指向原始数据的指针的副本,所以当在函数内部通过这个指针修改数据时,实际上修改的是原始变量的值。

结构体的值传递

接下来,通过一个结构体的例子来说明值传递的概念。简单示例代码如下:

package main
 
import "fmt"
 
type Person struct {
    Name string
    Age  int
}
 
func modifyStruct(p Person) {
    p.Name = "Alice"
    p.Age = 30
}
 
func main() {
    originalPerson := Person{Name: "Bob", Age: 25}
    modifyStruct(originalPerson)
    fmt.Println(originalPerson) // 输出 {Bob 25},未被修改
}

在上面的例子中,originalPerson 是一个 Person 类型的结构体。当被传递到 modifyStruct 函数时,传递的是这个结构体的副本。因此,函数内部对结构体的修改不会影响到原始的 originalPerson。

结构体指针的传递

最后来看一个结构体指针的例子,理解如何通过指针来修改结构体的字段。简单示例代码如下:

package main
 
import "fmt"
 
type Person struct {
    Name string
 
    Age int
}
 
func modifyStructPointer(p *Person) {
    p.Name = "路多辛"
    p.Age = 20
}
 
func main() {
    originalPerson := &Person{Name: "luduoxin", Age: 25}
    modifyStructPointer(originalPerson)
    fmt.Println(*originalPerson) // 输出 {路多辛 20} ,被修改
}

在这个例子中,传递了 originalPerson 的地址给 modifyStructPointer 函数。这次传递的是一个指向结构体的指针的副本,所以在函数内部对这个指针所指向的结构体的修改,实际上改变了原始的`originalPerson`结构体。

小结

Go 语言中的参数传递总是值传递,意味着传递的总是变量的副本,无论是基本数据类型还是复合数据类型。由于复合数据类型(如切片、映射、通道、接口和指针)内部包含的是对数据的引用,所以在函数内部对这些参数的修改可能会影响到原始数据。理解这一点对于编写正确和高效的Go代码至关重要。

另外即使是引用类型,比如切片,当长度或容量(比如使用 append 函数)发生变化了,可能会导致分配新的底层数组。这种情况下,原始切片不会指向新的数组,但是函数内部的切片会。因此,如果想在函数内部修改切片的长度或容量并反映到外部,应该传递一个指向切片的指针。

以上就是一文带你深入了解Golang中的参数传递机制的详细内容,更多关于Go参数传递机制的资料请关注脚本之家其它相关文章!

相关文章

  • Go时间操作常用方法(推荐!)

    Go时间操作常用方法(推荐!)

    平时开发过程中,时间相关的操作用的还是很多的,下面这篇文章主要给大家介绍了关于Go时间操作常用方法的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-06-06
  • 初步解读Golang中的接口相关编写方法

    初步解读Golang中的接口相关编写方法

    这篇文章主要介绍了Golang中的接口相关编写方法,是Go语言入门学习中的基础知识,需要的朋友可以参考下
    2015-11-11
  • 使用Go语言编写简洁代码的最佳实践

    使用Go语言编写简洁代码的最佳实践

    简洁的代码对于创建可维护、可阅读和高效的软件至关重要,Go 是一种强调简单和代码整洁的语言,在本文中,我们将结合代码示例,探讨编写简洁 Go 代码的最佳实践,需要的朋友可以参考下
    2023-09-09
  • 解析golang中的并发安全和锁问题

    解析golang中的并发安全和锁问题

    本文我们来学习一下golang中的并发安全和锁问题,文章通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2021-11-11
  • go语言中函数与方法介绍

    go语言中函数与方法介绍

    这篇文章介绍了go语言中的函数与方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-07-07
  • Golang通道阻塞情况与通道无阻塞实现小结

    Golang通道阻塞情况与通道无阻塞实现小结

    本文主要介绍了Golang通道阻塞情况与通道无阻塞实现小结,详细解析了通道的类型、操作方法以及垃圾回收机制,从基础概念到高级应用,具有一定的参考价值,感兴趣的可以了解一下
    2024-03-03
  • Go语言实现牛顿法求平方根函数的案例

    Go语言实现牛顿法求平方根函数的案例

    这篇文章主要介绍了Go语言实现牛顿法求平方根函数的案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • 轻松入门:使用Golang开发跨平台GUI应用

    轻松入门:使用Golang开发跨平台GUI应用

    Golang是一种强大的编程语言,它的并发性和高性能使其成为开发GUI桌面应用的理想选择,Golang提供了丰富的标准库和第三方库,可以轻松地创建跨平台的GUI应用程序,通过使用Golang的GUI库,开发人员可以快速构建具有丰富用户界面和交互功能的应用程序,需要的朋友可以参考下
    2023-10-10
  • Go语言对前端领域的入侵WebAssembly运行原理

    Go语言对前端领域的入侵WebAssembly运行原理

    这篇文章主要为大家介绍了不安分的Go语言对Web 前端领域的入侵WebAssembly运行原理实例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07
  • golang http 连接超时和传输超时的例子

    golang http 连接超时和传输超时的例子

    今天小编就为大家分享一篇golang http 连接超时和传输超时的例子,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-07-07

最新评论