go切片参数传递用值还是指针

简介: go切片参数传递用值还是指针

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。

Go 中常用的切片 slice 数据结构是动态数组,切片长度并不固定,在容量不足的时候会自动扩容。

切片实质上是对一个底层数组的抽象视图,由 Go 运行时维护。在运行时,切片由如下的 SliceHeader 结构体表示,其中 Data 字段是指向底层数组的指针,Len 表示当前切片的长度,而 Cap 表示当前切片的容量,也就是 Data 数组的大小。

type SliceHeader struct {
    Data uintptr
    Len  int
    Cap  int
}

切片作为参数入参

我们知道 slice 是一个指针类型,所以我们可能会习惯性地认为:传递切片,等同于传递指针,函数内部对切片的修改,将会影响到函数外部的切片。这一习惯性认知在大部分情况下都是正确的,如以下代码所示:在 test 函数中修改切片,外部的 TestSlice 受到了影响。

func test(s []string) {
  for i := 0; i < len(s); i++ {
    s[i] = "b"
  }
}

func TestSlice(t *testing.T) {
  s := []string{"a", "b"}
  fmt.Println(s)
  test(s)
  fmt.Println(s)
}

输出:

[a b]
[b b]

我们对上面的代码做一些修改,在调用函数的时候触发切片的扩容机制,然后再看看输出:

func test1(s []string) {
  s = append(s, "b1")

  for i := 0; i < len(s); i++ {
    s[i] = "b"
  }
}

func TestSlice1(t *testing.T) {
  s := []string{"a", "b"}
  fmt.Println(s)
  test1(s)
  fmt.Println(s)
}

输出:

[a b]
[a b]

我们可以发现,test1 里面对切片的修改并没有完全影响到外部的切片。

原因

在 Go 中,函数参数传递机制为 值拷贝。

将切片做为函数参数传递,实际上是拷贝了 SliceHeader 结构体传入参数,结构体包含了指向底层数组的指针,因此在函数内部修改切片,操作的底层数组是一样的。

但是如果函数内的切片触发了切片扩容(如:使用 append 追加元素),Go 运行时会为切片分配一块新的内存空间并将原切片的所有元素拷贝过去,函数内部切片的底层数组指针指向了 新分配 的内存空间,而函数外部切片底层数组指针仍指向 分配前 的地址空间,由此出现了内外切片不一致的情形。

建议

  • 操作不涉及切片容量变化,直接传递切片
  • 操作涉及切片容量变化,且需要反馈给调用放,传递切片指针。


目录
相关文章
|
存储 JSON 安全
Go语言切片,使用技巧与避坑指南
Go语言中的切片(Slice)是动态引用数组的高效数据结构,支持扩容与截取。本文从切片基础、常用操作到高级技巧全面解析,涵盖创建方式、`append`扩容机制、共享陷阱及安全复制等内容。通过代码示例详解切片特性,如预分配优化性能、区分`nil`与空切片、处理多维切片等。掌握这些核心知识点,可编写更高效的Go代码。
566 2
|
存储 Go 索引
go语言中数组和切片
go语言中数组和切片
451 7
|
Go 索引
Go语言中,遍历数组或切片
在Go语言中,遍历数组或切片
437 6
|
存储 安全 Java
【Golang】(4)Go里面的指针如何?函数与方法怎么不一样?带你了解Go不同于其他高级语言的语法
结构体可以存储一组不同类型的数据,是一种符合类型。Go抛弃了类与继承,同时也抛弃了构造方法,刻意弱化了面向对象的功能,Go并非是一个传统OOP的语言,但是Go依旧有着OOP的影子,通过结构体和方法也可以模拟出一个类。
602 2
|
测试技术 Go API
Go 切片导致 rand.Shuffle 产生重复数据的原因与解决方案
在 Go 语言开发中,使用切片时由于其底层数据共享特性,可能会引发意想不到的 Bug。本文分析了 `rand.Shuffle` 后切片数据重复的问题,指出原因在于切片是引用类型,直接赋值会导致底层数组共享,进而影响原始数据。解决方案是使用 `append` 进行数据拷贝,确保独立副本,避免 `rand.Shuffle` 影响原始数据。总结强调了切片作为引用类型的特性及正确处理方法,确保代码稳定性和正确性。
472 82
|
数据采集 机器学习/深度学习 存储
Go语言实战案例 - 找出切片中的最大值与最小值
本案例通过实现查找整数切片中的最大值与最小值,帮助初学者掌握遍历、比较和错误处理技巧,内容涵盖算法基础、应用场景及完整代码示例,适合初学者提升编程能力。
|
安全 Go 开发者
Go语言之切片的原理与用法 - 《Go语言实战指南》
切片(slice)是Go语言中用于处理变长数据集合的核心结构,基于数组的轻量级抽象,具有灵活高效的特点。切片本质是一个三元组:指向底层数组的指针、长度(len)和容量(cap)。本文详细介绍了切片的声明与初始化方式、基本操作(如访问、修改、遍历)、长度与容量的区别、自动扩容机制、共享与副本处理、引用类型特性以及常见陷阱。通过理解切片的底层原理,开发者可以更高效地使用这一数据结构,优化代码性能。
554 13
|
Go 索引
Go语言中使用切片需要注意什么?
本文详细讲解了Go语言中切片(Slice)的使用方法与注意事项。切片是对数组连续片段的引用,具有灵活的操作方式。文章从定义与初始化、长度与容量、自动扩容、共享底层数组、复制、边界检查、零值到拼接等方面展开,并配以示例代码演示。通过学习,读者可深入了解切片的工作原理及优化技巧,避免常见陷阱,提升编程效率与代码质量。
374 2
|
Go 索引
go语言for遍历数组或切片
go语言for遍历数组或切片
565 62
|
存储 Go
Go 语言入门指南:切片
Golang中的切片(Slice)是基于数组的动态序列,支持变长操作。它由指针、长度和容量三部分组成,底层引用一个连续的数组片段。切片提供灵活的增减元素功能,语法形式为`[]T`,其中T为元素类型。相比固定长度的数组,切片更常用,允许动态调整大小,并且多个切片可以共享同一底层数组。通过内置的`make`函数可创建指定长度和容量的切片。需要注意的是,切片不能直接比较,只能与`nil`比较,且空切片的长度为0。
573 3
Go 语言入门指南:切片

热门文章

最新文章