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
}

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

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
}

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
}

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
		}
	}
}

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

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
}

猜你喜欢

转载自blog.csdn.net/qq_41341757/article/details/126745377
今日推荐