最本质的区别
值类型:内存中变量存储的是具体的值 比如: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进行操作会导致原来的数值也发生改变。
特别声明:以上文章内容仅代表作者本人观点,不代表变化吧观点或立场。如有关于作品内容、版权或其它问题请于作品发表后的30日内与变化吧联系。
- 赞助本站
- 微信扫一扫
-
- 加入Q群
- QQ扫一扫
-
评论