基本数据类型是Go语言世界中的原子,以不同的方式组合基本数据类型得到的就是复合数据类型。复合类型是通过组合基础类型,来表达更加复杂的数据结构,即使用其他类型定义的类型,因而复合类型又称之为派生类型。本章主要介绍:指针、数组array、切片slice、字典map、结构体。
数据类型分为值类型与引用类型,在学习复合数据类型前,我们需要研究一下
- 1、数值型复合类型:
- 2.1 数组(array)
- 2.2 结构体(struct)
- 2、引用型复合类型:
- 3.1 指针(pointer)
- 3.2 切片(slice)
- 3.3 字典(map)
- 3.4 通道(chan)
- ps:函数也属于引用类型
基础类型(数字、字符串、字符、布尔)以及数值型复合类型都属于值类型
| |
| 1、对于值类型,即便我们在声明的时候都没有为其初始化值,那么编译器会依据它们的零值为它们申请好内存空间(分配于栈上),所以对于值类型我们都不必费心为其申请内存空间 |
| var a int |
| var b string |
| var c bool |
| var d [2]int |
| fmt.Println(&a) |
| |
| 2、值类型的变量赋值操作,如 j = i ,实际上是在内存中将 i 的值进行了拷贝,如果修改某个变量的值i=3,不会影响另一个 |
| 例1: |
| var a =10 |
| b := a |
| b = 101 |
| fmt.Printf("值%v,内存地址%p\n",a,&a) |
| fmt.Printf("值%v,内存地址%p\n",b,&b) |
| |
| 例2: |
| var c =[3]int{1,2,3} |
| d := c |
| d[1] = 100 |
| fmt.Printf("值%v,内存地址%p\n",c,&c) |
| fmt.Printf("值%v,内存地址%p\n",d,&d) |
引用型复合类型(指针、切片、字典、通道)、函数、接口类型都属于引用类型。
| |
| 1、对于引用类型,如果我们在声明的时候没有为其初始化“值”,那么默认零值为nil,nil代表空,编译器不会为其分配内存,而引用类型存在的意义在于引用了一个已经存在的内存空间,所以对于引用类型我们必须为其申请好内存才可以使用,需要用到函数new()和make() |
| |
| new()与make()的异同 |
| 相同点: |
| I、都是针对引用类型的内存空间分配操作 |
| II、分配的内存都在堆上 |
| III、第一个参数都是一个类型,而不是一个值 |
| 不同点: |
| I、make 只用于引用类型map, slice, channel的内存分配,返回的还是这三个引用类型本身,而new返回的是一个指针。 |
| II、new多用于匿名变量的空指针操作,如new(int),new(string), new(array)等,而且内存置为零,此外,大多数场景下new并不常用, |
| |
| 2、引用类型的变量赋值操作,如 j = i ,当然也是在内存中将 i 的值拷贝给了j,但是因为引用类型的变量直接存放的就是一个内存地址值(这个地址值指向的空间存的才是值),即i与j都是同一个地址。所以通过i或j修改对应内存地址空间中的值,另外一个也会修改。 |
| |
| 例如 |
| var a = []int{1,2,3,4,5} |
| b := a |
| b[1] = 10 |
| c := make([]int,5,5) |
| copy(c,a) |
| c[1] = 20 |
| fmt.Printf("值%v,内存地址%p\n",a,&a) |
| fmt.Printf("值%v,内存地址%p\n",b,&b) |
| fmt.Printf("值%v,内存地址%p\n",c,&c) |
| d := &a |
| a[1] = 11 |
| fmt.Printf("值是%v,内存地址%p\n",*d,d) |
| fmt.Printf("值是%v,内存地址%p\n",a,&a) |
a,b底层数组是一样的,即操作的都是同一个底层数组,但是上层切片不同,所以内存地址不一样。
强调1:引用类型的零值是nil,而nil只能与nil做相等性判断
| |
| var s []int |
| s = nil |
| s = []int(nil) |
| s = []int{} |
| |
| |
| var a []string |
| fmt.Println(a == nil) |
| |
| var b []int |
| fmt.Println(b == nil) |
| |
| var c = []int{} |
| fmt.Println(c == nil) |
强调2:关于函数
函数的参数传递机制是将实参的值拷贝一份给形参.只不过这个实参的值有可能是地址, 有可能是数据.
所以, 函数传参的传递其实本质全都是值传递,只不过该值有可能是数据(通常被简称为”值传递“),也有可能是地址(通常被简称为”引用传递“).