【拓展】Go语言基础加强
1、深浅拷贝
- 浅拷贝:仅仅拷贝的是变量的值,没有对指向的空间进行任何的拷贝。
- 深拷贝:将原有的变量的空间地址全部拷贝一份。
在 Go 语言中,变量的赋值操作默认是浅拷贝,即两个变量指向同一个内存地址。这意味着,如果修改其中一个变量的值,另一个变量的值也会发生变化。
对于复杂数据类型,如结构体和切片,我们有时需要进行深拷贝,即创建一个新的变量并将原变量的值复制到新变量中,而不是简单地复制指向原变量的指针。这样可以避免修改新变量的值对原变量造成影响。
(1) 对于结构体,可以使用结构体字面量进行深拷贝
package main
import "fmt"
type Person struct {
name string
age int
}
func main() {
p1 := Person{"zhangsan", 20}
p2 := Person{p1.name, p1.age} // 深拷贝
fmt.Println(p1, p2)
fmt.Println(&p1.name, &p2.name)
}
代码输出内容:
{zhangsan 20} {zhangsan 20}
0xc000008078 0xc000008090
(2) 对于切片,可以使用内置的 copy
函数进行深拷贝
package main
import "fmt"
func main() {
s1 := []int{1, 2, 3}
s2 := make([]int, len(s1))
copy(s2, s1)
fmt.Println(s1, s2)
fmt.Println(&s1[0], &s2[0])
}
代码输出内容:
[1 2 3] [1 2 3]
0xc000016138 0xc000016150
需要注意的是,如果切片中的元素是引用类型,则深拷贝只会复制指向原变量的指针,而不会复制指针所指向的值。这时,需要对每个元素进行深拷贝,以确保新变量中的元素与原变量中的元素互不影响。
2、切片传参
(1)切片作为函数参数可以修改切片中的元素,原因分析:
在Go语言中,切片是一种引用类型,它底层是一个指向数组的指针,同时也包含了长度和容量等信息。当我们将一个切片传递给一个函数时,实际上是将切片的引用(指针)传递给了函数,因此函数中对切片的任何修改都会影响到原切片。
(2)为什么在函数中使用append方法,不会改变原切片?
首先看一下案例:
package main
import "fmt"
func main() {
m := make([]int, 5, 5)
InitData(m)
fmt.Println(m)
}
func InitData(m []int) {
for i := 0; i < 5; i++ {
m = append(m, i)
}
}
以上代码是创建一个切片,使用函数对切片进行初始化操作,代码输出内容如下:
[0 0 0 0 0]
思考:我们使用append函数对切片做初始化了,为什么并没有改变切片的值呢?
答:在Go语言中,切片是一种引用类型。当我们将一个切片作为参数传递给函数时,实际上是将切片的引用传递给了函数。因此,函数中对切片的任何修改都会影响到原始切片。
但是,当我们使用append方法向切片中添加元素时,如果新的元素可以被容纳在原始切片的容量范围内,那么append方法会直接在原始切片中添加新元素,并返回一个指向原始切片的新切片。这个新切片与原始切片共享底层数组,但长度已经被更新为添加新元素后的长度。
如果新的元素无法被容纳在原始切片的容量范围内,那么append方法会创建一个新的底层数组,并将原始切片中的元素复制到新的底层数组中。然后,append方法会向新的底层数组中添加新元素,并返回一个指向新底层数组的新切片。这个新切片与原始切片不再共享底层数组。
因此,在函数中使用append方法,如果新元素可以被容纳在原始切片的容量范围内,那么原始切片会被修改。否则,原始切片不会被修改,而是返回一个指向新底层数组的新切片。
3、for range分析
- 作用:用户遍历容器类型的数据,列如:数组、切片、map等。
- range的本质是一个函数方法,使用时候可以加括号使用。
- 修改range得到后的value,不影响原始切片或数组。
(1) range的本质是一个函数方法,使用时候可以加括号使用:
package main
import (
"fmt"
)
func main() {
array := [3]int{100, 200, 300}
for i, v := range (array) { // i, v := range (array) 定义两个变量接收range函数返回值
array[i] = 3
fmt.Println(v)
}
fmt.Println(array)
}
代码输出内容:
100
200
300
[3 3 3]
(2)修改range得到后的value,不影响原始切片或数组:
package main
import "fmt"
type Class struct {
name string
age int
}
func main() {
stu1 := Class{"zhangsan", 1}
stu2 := Class{"lisi", 10}
stu3 := Class{"wangwu", 100}
s := []Class{stu1, stu2, stu3}
for _, values := range s {
values.age = values.age + 10000 // 对每个age进行更新操作
}
fmt.Println(s)
}
代码输出内容:
[{zhangsan 1} {lisi 10} {wangwu 100}]
思路:我对每个age进行更新了,为什么输出时没有进行更新呢?
答案:range是一个函数,age只是对range函数中进行修改了,并不会影响到原切片值。