【拓展】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函数中进行修改了,并不会影响到原切片值。

posted @ 2023-04-05 14:08  乱七八糟博客备份  阅读(27)  评论(0编辑  收藏  举报