复合类型
数组类型
数组在任何编程语言中,都是高频使用的类型,所以学习时也要重点掌握。首先,就是掌握如何声明数组与实例化数组,示例如下:
var name[SZIE] type //创建数组,但不初始化 var num[10] int //创建数组,并初始化 var num = [10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
数组可以直接通过num[i]去修改访问值,这里不再赘述。
结构体介绍
学过C语言的,对结构体应该并不陌生。其实Go语言的结构体与C基本差不多,下面,我们来看看如何定义以及使用:
//语法 type 类型名 struct{ 字段1 类型1 字段2 类型2 //..... } //定义 type User struct { name string age int }
接着,我们再来看看定义并赋值后,如何使用结构体。
示例如下:
type User struct { name string age int } func main() { var lyj User=User{name:"liyuanjing",age:29} var fxy User=User{name:"fengxinyao",age:31} fmt.Println(lyj) fmt.Println(fxy) fmt.Println(lyj.age) fmt.Println(fxy.name) }
运行之后,效果如下:
可以发现,我们可以直接把结构体当作一个类型来使用。也就是说,在Go语言中,我们可以自己通过结构体定义数据类型。
而使用结构体,可以直接输出,也可以通过[变量.属性]的方式,获取结构体中的单个值。同样的,结构体也可以时指针变量,这一点与C语言一样。
切片类型
切片(slice)是对数组的一个连续“片段”的引用,所以切片也可以看作一个引用类型,或者相当于Python中的list。
切片的内部结构包含内存地址、大小以及内容,一般用于快速地操作一块数据集合。如下图所示:
其中,切片的指针指向数组,长度代表当前切片的长度,容量是当前切片的容量。容量总是大于或等于切片的长度,而且切片默认指向一段连续的内存区域。
从指定范围生成切片
切片与数组密不可分,如果将数组理解为一栋火车厢,那么切片就是把不同连续车厢出租给使用者。在出租的过程中,需要选择开始车厢与结束车厢,这个过程就会生成切片。示例如下:
var sliceBuilder [10]int for i :=0;i<10;i++{ sliceBuilder[i]=i+1 } fmt.Println(sliceBuilder[5:7]) fmt.Println(sliceBuilder[8:]) fmt.Println(sliceBuilder[:5])
运行之后,控制台输出如下:
看过前面字符串获取子字符串的用户,肯定会问,切片有何区别?
怎么说呢?切片有点像C语言的指针。指针可以做运算,但代价是内存操作越界。切片在指针的基础上增加了大小,约束了切片对应的内存区域。
在切片的使用过程中,无法对切片内部的地址和大小进行手动调整,因此切片比指针更安全强大。
重置切片
如果把切片开始与结束位置都设置为0,则生成的切片将变空,代码如下:
var sliceBuilder [10]int for i :=0;i<10;i++{ sliceBuilder[i]=i+1 } fmt.Println(sliceBuilder[0:0])
记住是清空,不是全部赋值为0,也就是说充值的切片没有任何元素。运行之后,效果如下:
直接声明切片
切片也是可以直接被声明的,并不一定需要从数组操作。其语法如下:
var name []Type
注意,这个看上去与数组声明的方式差不多,但有本质区别,不信的读者回头看看上面的数组。数组定义必须给定你需要创建一个多少元素的数组,而切片不需要。
示例:
var sliceInt []int var sliceString []string var emptySlice =[]int{} fmt.Println(sliceInt,sliceString,emptySlice) fmt.Println(len(sliceInt),len(sliceString),len(emptySlice)) fmt.Println(sliceString==nil) fmt.Println(sliceInt==nil) fmt.Println(emptySlice==nil)
运行之后,效果如下:
需要注意的是,切片是动态结构,只能与nil判定相等,不能互相判定相等。在声明了切片之后,可以使用append()方法向切片中添加元素。如果需要创建一个指定长度的切片,则可以使用make()方法创建。
sliceInt :=make([]int,6,10) fmt.Println(sliceInt)
上面声明了一个长度为6,容量为10的切片,控制台会输出6个0的切片。
用make()函数生成的切片会发生内存分配操作。但如果给定了开始与结束位置(包括切片复位)的切片,则只是将新的切片结构指向已经分配的内存区域。设置开始与结束位置,不会发生内存分配操作。
Map
Map就是“键值对”的无序集合。元素包含一个key,与一个Value。有时候也会成为字典。其定义的语法如下:
var student map[string]string var user = map[string]string{"liyuanjing": "29", "fengxiangyao": "29"} student =make(map[string]string)//删除这行在测试 student["liyuanjing"] = "29" fmt.Println(student) fmt.Println(user)
运行之后,控制台输出如下:
如上面注释一样,如果删除make函数那一样,肯定会报错。这是因为在声明student 后并未初始化它,所以它的值是nil,不指向任何内存地址。需要通过make方法分配确定的内存地址,程序修改后即可正常运行。
在我们的项目中,有时候Key并不仅仅只对应一个Value,如果要key对应多个值,那么Map应该怎么做?示例如下:
map1 := make(map[int][]int) map1[22]=[]int{1,2,3,4,5} fmt.Println(map1)
运行之后,效果如下: