• Go语言中的参数传递问题


    一: 传递参数知识点汇总

    • 1: Go语言中函数之间的传递, 全部是值传递。
    • 2: Go语言中,普通的值传递, 将会重新拷贝一份内容, 传递到函数中。如果是指针传递, 会创建一个新的指针, 但是新的指针还是指向原来的内存空间。
    • 3: 如何选择变量传递还是指针传递
      • 不想变量被修改, 选择变量传递。想要被修改, 选择指针传递。
      • 变量特别大,考虑到节约空间, 选择指针传递。
    • 4: 什么时间触发创建副本?
      • 赋值的时候就会创建对象副本。
    • 5: 数组, 切片, 字典,在初始化的时候,如果有其他的变量, 全部拷贝一份新的变量副本。
    • 6: 循环遍历出来的变量也是原来变量的副本。
    • 7: 管道中发送对象, 这个对象也是副本。

    二:传参测试

    2.1: 测试Go语言的传参都是值传递(副本传递)

    • Go语言所有的值在赋值的时候, 都是先拷贝一份, 然后将拷贝的内容赋值给新的函数参数变量。
    package main
    
    import "fmt"
    
    type People struct {
    	Name string
    	Age  int8
    }
    
    func passTest(p People) {
    	fmt.Printf("传递到函数中的地址: %p\n", &p)
    	// 传递到函数中的地址: 0xc000118018
    }
    
    func main() {
    	myName := People{Name: "renshanwen", Age: 18}
    	fmt.Printf("主函数初始化的变量地址: %p\n", &myName)
    	// 主函数初始化的变量地址: 0xc000118000
    	passTest(myName)
    	fmt.Printf("不会影响到主函数的变量: %p\n", &myName)
    	//不会影响到主函数的变量: 0xc000118000
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    2.2: 传递指针类型,也是复制指针, 只不过复制后的指针和之前的指针指向相同的内存空间

    package main
    
    import "fmt"
    
    type People struct {
    	Name string
    	Age  int8
    }
    
    func passTest(p *People) {
    	fmt.Printf("传递到函数中的指针变量的内存地址: %p,指针变量指向的内存地址:%p\n", &p, p)
    	//传递到函数中的指针变量的内存地址: 0xc000012038,指针变量指向的内存地址:0xc000010030
    	p.Name = "chengcheng" // 修改名字
    }
    
    func main() {
    	myName := &People{Name: "renshanwen", Age: 18}
    	fmt.Printf("主函数初始化指针变量的内存地址: %p, 指针变量指向的内存地址:%p\n", &myName, myName)
    	//主函数初始化指针变量的内存地址: 0xc000012028, 指针变量指向的内存地址:0xc000010030
    	passTest(myName)
    	fmt.Printf("被修改后的名字: %s\n", myName.Name)
    	//被修改后的名字: chengcheng
    	fmt.Printf("主函数被影响后指针变量的内存地址: %p, 指针变量指向的内存地址:%p\n", &myName, myName)
    	//主函数被影响后指针变量的内存地址: 0xc000012028, 指针变量指向的内存地址:0xc000010030
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    2.3:所有的赋值操作都会触发创建副本

    package main
    
    import "fmt"
    
    func main() {
    	myName := "renshanwen"
    	var myName2 = myName
    	fmt.Printf("myName的地址是%p\n", &myName)
    	// myName的地址是0xc000096210
    	fmt.Printf("myName2的地址是%p\n", &myName2)
    	// myName2的地址是0xc000096220
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2.4: 数组,切片,字典,在初始化的时候,如果有其他的变量, 全部拷贝一份新的变量副本

    • 数组测试
    package main
    
    import "fmt"
    
    type people struct {
    	Name string
    	Age  int8
    }
    
    func main() {
    	var myName = people{Name: "shanwen", Age: 23}
    	fmt.Printf("myName的内存地址是%p\n", &myName)
    	//myName的内存地址是0xc000010030
    	testArray := [1]people{myName}
    	fmt.Printf("数组内myName的内存地址是%p\n", &testArray[0])
    	//数组内myName的内存地址是0xc000010048
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    2.5: 循环遍历出来的变量也是原来变量的副本

    package main
    
    import "fmt"
    
    type People struct {
    	Name string
    	Age  int8
    }
    
    var thisPeople = People{Name: "renshanwen", Age: 35}
    
    func main() {
    	array := [...]People{thisPeople, thisPeople, thisPeople}
    	fmt.Printf("数组中的首个变量所在内存中的地址是: %p, \n", &array[0])
    	//数组中的首个变量所在内存中的地址是: 0xc0000b6000
    	for i, item := range array {
    		if i == 0 {
    			fmt.Printf("遍历出的变量的内存地址是: %p, \n", &item)
    			//遍历出的变量的内存地址是: 0xc0000a0018
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    2.6: 函数类型本质也是指针类型

    package main
    
    import "fmt"
    
    func main() {
    	f1 := func(i int) {}
    	fmt.Printf("f1:\t\t %+v, \t\t内存地址:%p\n", f1, &f1)
    	f2 := f1
    	fmt.Printf("f2:\t\t %+v, \t\t内存地址:%p\n", f2, &f2)
    }
    // f1:              0x108e680,             内存地址:0xc000100018
    // f2:              0x108e680,             内存地址:0xc000100028
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2.7: 管道中发送对象, 这个对象也是副本

    package main
    
    import "fmt"
    
    type Bird struct {
    	Age  int
    	Name string
    }
    
    var parrot1 = Bird{Age: 1, Name: "Blue"}
    
    func main() {
    	ch := make(chan Bird, 3)
    	fmt.Printf("parrot1:\t\t %+v, \t\t内存地址:%p\n", parrot1, &parrot1)
    	//parrot1:                 {Age:1 Name:Blue},             内存地址:0x1139250
    	ch <- parrot1
    	parrot1.Age = 2
    	p := <-ch
    	fmt.Printf("parrot%d:\t\t %+v, \t\t内存地址:%p\n", 2, p, &p)
    	//parrot2:                 {Age:1 Name:Blue},             内存地址:0xc000010048
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
  • 相关阅读:
    正则表达式(常用最新版)
    Greenplum数据库故障分析——能对数据库base文件夹进行软连接嘛?
    【LeetCode】308d:给定条件下构造矩阵
    2023高教社杯数学建模A题B题C题D题E题思路模型 国赛建模思路分享
    8.2模拟赛总结
    opencv
    我有一篇Java Stream使用手册,学了就是你的了!
    Opencv中的RNG-随机绘图
    C++征途 --- 内建函数对象
    【MySQL】事务
  • 原文地址:https://blog.csdn.net/qq_41341757/article/details/126745377