博客主页:🏆看看是李XX还是李歘歘 🏆
🌺每天不定期分享一些包括但不限于计算机基础、算法、后端开发相关的知识点,以及职场小菜鸡的生活。🌺
💗点关注不迷路,总有一些📖知识点📖是你想要的💗
目录
Go的数据类型
基本数据类型
复合数据类型
深拷贝和浅拷贝
概念
代码解释
传递
本文会详细讲一下Go的理论知识,包括数据类型,深拷贝和浅拷贝,传递
Go的数据类型
在Go中其数据类型分为基本数据类型和复合数据类型
基本数据类型
布尔型、整型、浮点型、字符型、复数型、字符串
基本数据类型全部都是值类型,都是可比的,但是需要注意的是在Go中字符型有两种表示:byte和rune,详情请参考:Go语言的rune和byte的区别
复合数据类型
非引用类型:数组、结构体
引用类型:指针、切片、映射、通道、函数
接口类型:接口
复合数据类型的可比性(是否可以用==作为判断):
非引用类型:数组、结构体也属于值类型,但是它们的可比性取决于其中变量的可比较性;引用类型中指针和通道是可比的,切片、映射是不可比的,函数可以通过反射获取函数指针进行比较;接口类型是可比较的。
函数的比较:
package main import ( "fmt" "reflect" ) func lcc() { fmt.Println(1) } func lyh() { fmt.Println(1) } func main() { func1 := reflect.ValueOf(lcc) func2 := reflect.ValueOf(lcc) func3 := reflect.ValueOf(lyh) fmt.Println(func2 == func1) // true fmt.Println(func2 == func3) // false }
其中切片、map和channel的知识点可以参考:
(47条消息) Go的Slice和数组_李歘歘的博客-CSDN博客_go slice 元素个数
(47条消息) 浅聊go的map_李歘歘的博客-CSDN博客_go map每次迁移多少数据
(47条消息) 浅聊goroutine和channel_李歘歘的博客-CSDN博客
深拷贝和浅拷贝
概念
深拷贝:拷贝的是数据本身,创造一个样的新对象,新创建的对象与原对象不共享内存,新创建的对象在内存中开辟一个新的内存空间,新对象值修改时不会影响原对象值。既然内存地址不同,释放内存地址时分别释放。
值类型的数据(基本数据类型+复合数据类型的非引用类型),默认全部采用深拷贝。
浅拷贝:拷贝的是数据地址,只复制指向的对象的指针,此时新对象和老对象指向的内存地址是一样的,新对象值修改时老对象也会变化。释放内存地址时,同时释放内存地址。
引用类型的数据,默认全部采用浅拷贝。
引用类型,想实现深拷贝,就不能直接 := ,而是要先 new ,再赋值。slice也可以使用copy函数进行深拷贝。
深拷贝会拷贝数据(两变量存储地址不同,拷贝结束互不影响)。浅拷贝只会拷贝内存的地址(即使拷贝结束,还是互相影响)
代码解释
深拷贝和浅拷贝
package main
import "fmt"
func main() {
// slice是浅拷贝,改变了a的值,b也会变化,而且内存空间是同一个
a := []int{1}
b := []int{2}
fmt.Println(a[0], &a[0])
fmt.Println(b[0], &b[0])
b = a
a[0] = 3
fmt.Println(a[0], &a[0])
fmt.Println(b[0], &b[0])
fmt.Println("----------------------------")
// array是深拷贝,改变了c的值,d的值不变,而且内存空间是两个
c := [1]int{1}
d := [1]int{2}
fmt.Println(c[0], &c[0])
fmt.Println(d[0], &d[0])
d = c
c[0] = 3
fmt.Println(c[0], &c[0])
fmt.Println(d[0], &d[0])
}
slice实现深拷贝
package main
import "fmt"
func main() {
// slice的深拷贝实现----copy函数,改变了c的值,d的值不变,而且内存空间是两个
a := []int{1}
b := []int{2}
fmt.Println(a[0], &a[0])
fmt.Println(b[0], &b[0])
copy(a, b) // copy是深拷贝
a[0] = 3
fmt.Println(a[0], &a[0])
fmt.Println(b[0], &b[0])
fmt.Println("----------------------------")
}
传递
官方给的文档说明,go中的所有传递都是值传递,都是一个副本,一个拷贝。
在 go 语言中 值类型赋值都是深拷贝 ,引用类型一般都是浅拷贝。但是实际传递过程中,值类型会生成一个副本进行传递,引用类型会生成一个指针副本进行传递,所以在go中的所有传递都是值传递。
有的同学可能不懂为啥引用类型也是值传递?
引用类型的时候,他们的结构体中并没有直接保存数据,而是保存了指向数据的指针,那么在传递时候,就拷贝了一份它们自己的一份结构体,包括只想地址的指针,结构体里面具体保存的指针指向的地址还是同一份,没有变化的。所以这也就说明函数中为什么可以改变引用类型变量的值了,因为底层指针指向的地址是同一个。
func lcc(a int) {
fmt.Println(&a)
}
func lyh(a []int) {
fmt.Println(&a[0])
}
func main() {
a := 1
fmt.Println(&a)
lcc(a)//值类型,复制了一个新的值,所以是一个新的地址
b := []int{1}
fmt.Println(&b[0])
lyh(b)//引用类型,复制了一个指向该地址的指针,所以说地址不变
}