Go语言中的值类型和引用类型

最本质的区别

值类型:内存中变量存储的是具体的值 比如: var num int num存放的是具体的int值

但是变量在内存中的地址可以通过 &num 来获取

引用类型:变量直接存放的就是一个地址值,这个地址值指向的空间存的才是值。

例如:

 var ptr *int =& num

值类型,引用类型都包括哪些

基本的数据类型 int系列,float系列,bool,string, 数组和结构体struct

引用类型包括指针,slice切片,map ,chan ,interface

值类型和引用类型的使用特点

值类型 直接存放值,内存通常在栈中分配

应用类型变量存储的地址(也就是通过指针访问类型里面的数据),通常真正的值在堆上分配。当么有变量引用这个地址的时候,该值会被gc回收。

实例详解值类型和引用类型

1.数组array和切片slice的实例:

定义了一个数组a,它是值类型,复制给b是copy,当b发生变化后a并不会发生任何变化,程序的执行结果如下所示:

func main() {
	a :=[5]int{1,2,3,4,5}
	b := a
	b[2] = 8
	fmt.Println(a, b) //[1,2,3,4,5] [1,2,8,4,5]
}

切片却相反

func main() {
	a :=[]int{1,2,3,4,5}
	b := a
	b[2] = 8
	fmt.Println(a, b) //[1,2,8,4,5] [1,2,8,4,5]
}

2.来一个更复杂的例子,结构体和map

//Count代表计数器的类型
type Counter struct {
	count int
}

func add1(s map[string]int)  {
	s["count"]++
}

func add2(s map[string]Counter)  {
	counter := s["count"]
	counter.count++
}

func add3(s map[string]*Counter)  {
	counter := s["count"]
	counter.count++
}

func add4(s Counter) {
	s.count++
}

func main() {
	m1 := make(map[string]int)
	add1(m1)
	add1(m1)
	println(m1["count"])
	m2 := map[string]Counter{"count":Counter{20}}
	add2(m2)
	//temp := m2["count"]
	//temp.count++
	println(m2["count"].count)
	m3 := map[string]*Counter{"count":&Counter{20}}
	add3(m3)
	println(m3["count"].count)
	m4 := Counter{20}
	add4(m4)
	println(m4.count)
}

结果为:

2
20
21
20

首先明确结构体是值类型,map是引用类型。

我们按m1,m4,m2,m3的顺序来讲解。

m1 是一个从string到int,声明的时候进行了零初始化,也就是一开始默认值为0。由于m1是一个引用类型,所以传递给add1的时候会拷贝其底层数据的指针,然后在然后通过指针直接进行操作。

而m4是一个结构体,是值类型。所以传递给add4的时候,是对其内存上的值拷贝,也就是add4中的s所在的内存块跟m4不一样了。因此,在add4中的任何操作并不会对m4造成影响。

m2,m3是结构体和map的结合。

m2不会改变,主要是因为add2中使用:=重新声明了counter,由于是对象是值类型,所以也就类似于第一个实例那样,只是单纯的进行了值拷贝。

m3是的add3中虽然看起来一样。但实际上counter是一个指针,所以对counter进行操作会导致原来的数值也发生改变。


撩我?
我的公众号:Kyda
在这里插入图片描述

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Go语言的 map 和 slice 都是非常常用的数据结构,它们的实现都是基于底层的数组实现的。 ### Map Go语言的 map 是一种无序的键对集合,可以通过 key 来快速查找对应的 value。map 的底层实现是一个哈希表,可以通过哈希函数将 key 映射到一个桶,每个桶存储一个链表,用于解决哈希冲突。 当我们向 map 添加一个元素时,会先根据 key 计算哈希,然后将元素插入到对应的桶。如果两个 key 的哈希相同,那么它们会被插入到同一个桶,采用链表方式解决冲突。 在对 map 进行遍历时,Go语言会按照 key 的哈希顺序遍历所有的桶,然后依次遍历每个桶的链表,因此 map 的遍历是无序的。 ### Slice Go语言的 slice 是一种动态数组,可以根据需要动态增加或删除元素。slice 的底层实现是一个数组指针、一个长度和一个容量。slice 本身不存储元素,而是引用底层数组的元素。 当我们向 slice 添加一个元素时,如果当前 slice 的长度已经达到了容量上限,Go语言会自动重新分配一个更大的底层数组,并将原有元素复制到新的数组。因此,slice 的容量也可以动态增加。 在对 slice 进行遍历时,可以使用 for range 循环,也可以使用下标方式访问 slice 的元素。 需要注意的是,map 和 slice 都是引用类型,因此在函数调用时,传递的是引用,而不是。如果修改了 map 或 slice 的元素,会影响到原始的 map 或 slice。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值