golang值引用和指针引用,结构体拷贝

本文详细探讨了Go语言中结构体的值拷贝与指针引用的区别,通过实例展示了不同拷贝方式下对变量值的影响,特别是在更新属性和序列化时的表现。内容涵盖普通声明、指针浅拷贝以及结构体new()声明的指针值拷贝,强调了指针引用在变量共享和修改时的特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

结构体拷贝

先声明一个狗狗的结构体

type Dog struct {
	name  string
	age   int8
}
// 重写String接口
func (Dog *Dog) String() string {
	return fmt.Sprintf("this dog's name: %s, it's age: %d",Dog.name,Dog.age)
}

1.普通声明及值拷贝

可以看到输出的时候并没有用到重写的String方法(毕竟不是指针)

func main() {
	d1 := Dog{"豆豆", 2}
	d2 := d1 //值拷贝
	d1.name = "小喵"
	fmt.Println(d1) // {小喵 2}
	fmt.Println(d2) // {豆豆 2}
}

2.普通声明及指针浅拷贝

可以看到输出的时候d1和d3的值是一样的,但是d1没有用到String,d3有

func main() {
	d1 := Dog{"豆豆", 2}
	d3 := &d1 //值拷贝
	d1.name = "小喵"
	fmt.Println(d1) // {小喵 2}
	fmt.Println(d3) // this dog's name: 小喵, it's age: 2
}

3.结构体的new()声明及指针的值拷贝

可以看到输出的时候d1和d3的值是不一样的

func main() {
	d1 := new(Dog) // d1指向空间1
	d3 := new(Dog) // d3指向空间2
	
	d1.name = "豆豆"
	d1.age = 2
	
	*d3 = *d1 // 指针的值拷贝,用*d1取出来的是"豆豆"结构体,赋值给*d3,那么d3指向的空间2会拷贝空间1的内容,两个空间还是独立的
	d1.name = "小喵"
	
	fmt.Println(d1) // this dog's name: 小喵, it's age: 2
	fmt.Println(d3) // this dog's name: 豆豆, it's age: 2
}
package main

import (
	"encoding/json"
	"fmt"
)

type User struct {
	UserId    int64  `json:"user_id"`
	RoomId    int64  `json:"room_id"`
	LiveIdStr string `json:"live_id"`
}

type UserManager struct {
	AppId string
	User1 User  `json:"user1"`
	User2 *User `json:"user2"`
}

func main() {
	tmpUser := User{
		UserId:    123456,
		RoomId:    333003,
		LiveIdStr: "zzt1",
	}
	tmpUser2 := User{
		UserId:    123456,
		RoomId:    333003,
		LiveIdStr: "zzt1",
	}
	um := UserManager{
		AppId: "app1080",
		User1: tmpUser,
		User2: &tmpUser2,
	}
	umCopy := um
	a, _ := json.Marshal(um)
	b, _ := json.Marshal(umCopy)
	fmt.Printf("um:%+v, umCopy:%+v  \n\n", string(a), string(b))
	um.AppId = "修改1080"
	um.User1.UserId = 999
	um.User2.UserId = 888
	a, _ = json.Marshal(um)
	b, _ = json.Marshal(umCopy)
	fmt.Printf("um:%+v, umCopy:%+v  \n\n", string(a), string(b))

}

输出:
um:{"AppId":"app1080","user1":{"user_id":123456,"room_id":333003,"live_id":"zzt1"},"user2":{"user_id":123456,"room_id":333003,"live_id":"zzt1"}}, 
umCopy:{"AppId":"app1080","user1":{"user_id":123456,"room_id":333003,"live_id":"zzt1"},"user2":{"user_id":123456,"room_id":333003,"live_id":"zzt1"}}  

um:{"AppId":"修改1080","user1":{"user_id":999,"room_id":333003,"live_id":"zzt1"},"user2":{"user_id":888,"room_id":333003,"live_id":"zzt1"}}, 
umCopy:{"AppId":"app1080","user1":{"user_id":123456,"room_id":333003,"live_id":"zzt1"},ser2":{"user_id":888,"room_id":333003,"live_id":"zzt1"}}  

引用

区分指针引用和值引用,使用struct的时候,明确指针引用和值引用的区别很重要。

1.值引用赋值 比如 a:=b,这样修改a.name=“ls”,不会影响到b.name,值引用是复制结构体,开辟一块新的内存空间, a只是b的一个副本,而不是指向b的引用。

2.指针引用赋值 比如 a:=&b ,这样修改a.name=“ls”,会影响到b.name,指针引用是指向结构体内存地址的引用,同一块内存空间
   
总结1。值引用不会互相影响两个变量值的独立,指针引用则会互相影响,因为他们都指向同一块内存地址

总结2:值引用只是复制的一个副本,不是指向内存地址的引用;指针引用,指针是指向内存地址的引用,因此使用它操作的不是结构体的副本而是本身。
指针引用的时候,比如 b:=&a,此时b是指针,因此必须使用*b对其进行引用(打印值)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值