diff --git a/2.2.md b/2.2.md index 92d20b6a..7f276039 100644 --- a/2.2.md +++ b/2.2.md @@ -168,12 +168,6 @@ GO中可以使用`+`来链接两个字符串 world` `` ` `` 括起的字符串为Raw字符串,即字符串在代码中的形式就是打印时的形式,没有字符转义,换行也将原样输出。 - -###GO数据底层的存储 - -下面这张图来源于 Russ Coxblog中的一篇介绍GO数据结构的文章,大家可以看到这些基础类型底层都是开辟了一块内存,然后存了相应的值 - -![](images/2.2.basic.png?raw=true) ###错误类型 Go内置有一个`error`类型,专门用来处理错误信息,GO的package里面还专门有一个包errors来处理错误 @@ -183,6 +177,12 @@ Go内置有一个`error`类型,专门用来处理错误信息,GO的package fmt.Print(err) } +###GO数据底层的存储 + +下面这张图来源于 Russ Cox blog中的一篇介绍GO数据结构的文章,大家可以看到这些基础类型底层都是开辟了一块内存,然后存了相应的值 + +![](images/2.2.basic.png?raw=true) + ##一些技巧 ###分组定义 @@ -249,12 +249,155 @@ array就是数组,它的定义如下`[n]type`,n表示数组的长度,type表 a := [3]int{1,2,3} //申明一个长度为3的数组 b := [10]int{1,2,3} //申明了一个长度为10的数组,其中前面三个元素初始化为1、2、3,其他默认为0 c := […]int{4,5,6} //可以省略长度,采用…,go会自动计算长度 - +也许你会说,我想数组里面还是数组,能实现吗?当然咯,GO支持嵌套数组,即多维数组,如下代码申明了一个而二维数组 + + //申明了一个二维数组,改数组是一个两个元素的数组,然后每个元素里面是4个int的元素 + double_array := [2][4]int {[4]int{1,2,3,4}, [4]int{5,6,7,8}} + //如果内部的元素和外部的一样,那么上面的申明可以简化,直接忽略内部的类型 + easy_array :=[2][4]int{{1,2,3,4},{5,6,7,8}} 数组的分配如下所示: ![](images/2.2.array.png?raw=true) + ###slice +我们很多的应用场景里面,数组不能满足我们的需求,因为我们不知道刚开始申明的时候到底需要多大的数组,也就是我们需要动态数组,GO里面我们叫做`slice` + +`slice`并不是真正意义上面的动态数组,而是一个引用类型,`slice`总是指向底层的一个`array`。`slice`的申明也可以像`array`一样,只要省略size + + //和什么array一样,只是少了长度 + var fslice []int + +接下来我们可以申明一个slice,并初始化数据,如下所示 + + slice := []byte {'a', 'b', 'c', 'd'} + +slice可以从一个数组或者一个已经存在的slice里面再次申明,`slice`通过array[i:j]来获取,i是数组的开始位置,j是结束位置,但不包含array[j],他的长度是j-i + + //申明一个含有是个字符元素的数组 + var array [10]byte {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'} + + //申明两个含有byte的slice + var a_slice,b_slice,c_slice []byte + + //a_slice指向数组的第2个元素开始,并到第五个元素结束, + a_slice = array[2:5] + //现在a_slice含有的元素: array[2], array[3] and array[4] + + // b_slice是另一个数组的slice. + b_slice = array[3:5] + // b_slice的元素是: array[3], array[4] + +他们的数据结构如下所示 + +![](images/2.2.slice.png?raw=true) + +slice有一些简便的操作 + + - slice的默认开始位置是0,ar[:n]等价于ar[0:n] + - slice的第二个序列默认是数组的长度,ar[n:]等价于ar[n:len(ar)] + - slice如果从一个数组里面直接获取,可以这样ar[:],因为默认第一个序列是0,第二个是数组的长度,即等价于ar[0,len(ar)] + +下面这个例子展示更多关于slice的操作 + + //申明一个数组 + var array [10]byte {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'} + //什么两个slice + var a_slice,b_slice []byte + + // 演示一些简便操作 + a_slice = array[:3] // 等价于a_slice = array[0:3] a_slice包含元素: a,b,c + a_slice = array[5:] // 等价于a_slice = array[5:9] a_slice包含元素: f,g,h,i,j + a_slice = array[:] // 等价于a_slice = array[0:9] 这样a_slice包含了全部的元素 + + //从slice获取slice + a_slice = array[3:7] // a_slice包含元素: d,e,f,g + b_slice = a_slice[1:3] //b_slice 包含a_slice[1], a_slice[2] 也就是含有: e,f + b_slice = a_slice[:3] //b_slice 包含 a_slice[0], a_slice[1], a_slice[2] 也就是含有: d,e,f + b_slice : a_slice[:] //b_slice包含所有a_slice的元素: d,e,f,g + +slice是引用类型,所以当引用改变值的时候,那么其他的所有引用都会改变该值,例如上面的a_slice和b_slice,如果修改了a_slice的值,那么b_slice相对应的值也会改变。 + +从概念上面来说slice想一个结构体,这个结构体包含了三个元素: +- 一个指针,指向数组中slice指定的开始位置 +- 长度,slice的长度 +- 最大长度,也就是slice开始位置到数组的最后位置的长度 + + array := [10]byte {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'} + slice := A[4:8] + +上面代码的真正存储结构如下图所示 + +![](images/2.2.slice2.png?raw=true) + +slice下面有几个有用的内置函数 + +- len 获取slice的长度 +- cap 获取slice的最大容量 +- append 向slice里面追加一个或者多个元素,然后返回一个和slice一样类型的slice +- copy 函数copy 从源slice src 复制元素到目标dst,并且返回复制的元素的个数 + + ###map +map也就是python中字典的概念,它的格式`map[keyType]valueType` + +我们看下面的代码,map的读取和设置也类似slice一样,通过来key操作,只是slice只有int的key,而map多了很多类型,可以是int,可以是string + + // 申明一个key是字符串,值为int的字典 + var numbers map[string] int + //另一种map的什么方式 + numbers = make(map[string]int) + numbers["one"] = 1 //赋值 + numbers["ten"] = 10 //赋值 + numbers["three"] = 3 + + fmt.Println("第三个数字是: ", numbers[3]) //读取数据 + // 打印出来如下: + //第三个数字是: 3 + +这个map就像我们平常看到的表格一样,左边列是key,右边列是值 + +使用map过程中需要注意的几点 +- map是无序的,每次打印出来的map都会不一样,他不能通过index获取,而必须通过key获取 +- map的长度是不固定的,也就是和slice一样,也是一种引用类型 +- 内置的len函数同样试用于map,返回map拥有的key的数量 +- map的值可以很方便的修改,通过`numbers["one"]=11`可以很容易的把key为`one`的字典值改为11 + +map的初始化可以通过key:val的方式初始化值,同时获取map内置有判断是否存在key的方式 + +删除map的元素通过delete + + //初始化一个字典 + rating := map[string]float32 {"C":5, "Go":4.5, "Python":4.5, "C++":2 } + //map可以有两个返回值,第二个返回值,如果不存在key,那么ok为false,如果存在ok为true + csharp_rating, ok := rating["C#"] + if ok { + fmt.Println("C# is in the map and its rating is ", csharp_rating) + } else { + fmt.Println("We have no rating associated with C# in the map") + } + + delete rating["C"] //删除key为C的元素 + + +上面说过了,map也是一种引用类型,如果两个map同时指向一个底层,那么一个改变,另一个也相应的改变 + + m = make(map[string][string]) + m["Hello"] = "Bonjour" + m1 = m + m1["Hello"] = "Salut" //现在m["hello"]的值已经是Salut了 + + +###make、new操作 + +`make`用于内建类型(`map`、`slice` 和`channel`)的内存分配。`new`用于各种类型的内存分配。 + +内建函数new 本质上说跟其他语言中的同名函数功能一样:new(T) 分配了零值填充的T 类型的内存空间,并且返回其地址,一个*T类型的值。用Go的术语说,它返回了一个指针,指向新分配的类型T的零值。有一点非常重要:new返回指针。 + +内建函数make(T, args)与new(T)有着不同的功能。它只能创建slice,map和channel,并且返回一个有初始值(非零)的T类型,而不是*T。本质来讲,导致这三个类型有所不同的原因是指向数据结构的引用在使用前必须被初始化。例如,一个slice,是一个包含指向数据(内部array)的指针,长度和容量的三项描述符;在这些项目被初始化之前,slice 为nil。对于slice,map 和channel,make 初始化了内部的数据结构,填充适当的 值。make返回初始化后的(非零)值。 + 下面这个图详细的解释了new和make之间的区别 ![](images/2.2.makenew.png?raw=true) + + + ## links * [目录]() * 上一章: [你好,GO](<2.1.md>) diff --git a/2.md b/2.md index 6ab5970c..2109f2b1 100644 --- a/2.md +++ b/2.md @@ -4,12 +4,11 @@ * 1. [你好,GO](2.1.md) * 2. [GO基础](2.2.md) * 3. [流程和函数](2.3.md) - * 4. [混合类型](2.4.md) - * 5. [高级类型](2.5.md) - * 6. [面向对象](2.6.md) - * 7. [并发](2.7.md) - * 8. [通讯](2.8.md) - * 9. [小结](2.9.md) + * 4. [高级类型](2.4.md) + * 5. [面向对象](2.5.md) + * 6. [并发](2.6.md) + * 7. [通讯](2.7.md) + * 8. [小结](2.8.md) GO是一门类似C的编译性语言,但是他的编译速度非常快,这门语言的关键字加起来也就二十五个,比英文字母的二十六还少一个,这对于我们来说是学习就变得简单了很多,先让我们看一眼这写关键字都长成怎么样: diff --git a/images/.DS_Store b/images/.DS_Store new file mode 100644 index 00000000..5008ddfc Binary files /dev/null and b/images/.DS_Store differ diff --git a/images/2.2.array.png b/images/2.2.array.png new file mode 100644 index 00000000..198dba20 Binary files /dev/null and b/images/2.2.array.png differ diff --git a/images/2.2.makenew.png b/images/2.2.makenew.png new file mode 100644 index 00000000..8e74d672 Binary files /dev/null and b/images/2.2.makenew.png differ diff --git a/images/2.2.slice.png b/images/2.2.slice.png new file mode 100644 index 00000000..422a09cf Binary files /dev/null and b/images/2.2.slice.png differ diff --git a/images/2.2.slice2.png b/images/2.2.slice2.png new file mode 100644 index 00000000..4d672e6b Binary files /dev/null and b/images/2.2.slice2.png differ