Go xmas2020 学习笔记 05、Arrays, Slices, and Maps

课程地址 go-class-slides/xmas-2020 at trunk · matt4biz/go-class-slides (github.com)

主讲老师 Matt Holiday

image-20220401081031592

05-Arrays, Slices, and Maps

In memory

image-20220402042140132

string、array、slice 在内存中是连续存储的,map不是连续存储的。


Array

image-20220402042243076

在创建数组的时候需要指定大小,如果不指定需要使用 ... ,图中 a、b 将是固定的 24 字节对象(int在64位操作系统上默认为int64),一旦设定不能改变。

d=b 中,由于数组只是一块内存,并不是像字符串那样的描述符,我们只是物理地复制了字节。当数组大小不一致时,无法进行拷贝复制。


Slice

image-20220402042810564

切片有描述符,指向一个特定的内存地址。它的工作方式类似于字符串的工作方式。

切片描述符包含 data、len、capacity。

append 方法需要把返回值重新赋给 a,假设 a 指向的内存区域已经满了,再添加元素就要开辟新的更大的内存区域存放。

a=b 表示 b 描述符的内容被拷贝到 a 描述符中。

e:=a 新建一个描述符,内容与 a 描述符内的一致。


切片可以被切片(截取)操作,就像从字符串(前面的os.Args[1:])中取出切片,从切片数组切片等。

package main

import "fmt"

func main() {
	t := []byte("string")

	fmt.Println(len(t), t)
	fmt.Println(t[2])
	fmt.Println(t[:2])
	fmt.Println(t[2:])
	fmt.Println(t[3:5], len(t[3:5]))
}
6 [115 116 114 105 110 103]
114
[115 116]
[114 105 110 103]
[105 110] 2

fence post error

image-20220402043131288

栅栏柱错误:假设我有三个栅栏部分,我必须有四个栅栏在他们旁边将它们固定住。(不懂直接看图)


Compare Array、Slice

image-20220402045248221

切片可以是任意长度,而且大部分 Go 的标准库使用切片作为参数。

切片是不能进行比较的,想进行比较可以使用数组。这也导致切片不能作为 Map Key。


数组可以作为一些算法必备的数组。大小固定,值不改变。近似于伪常量。注意,不能添加 const 常量关键字,只有数字,字符串,布尔值可以作为常量。

image-20220402045647614


Example

image-20220402045941511

a[0]=4 因为 a 只是 w 的值拷贝(数组),所以修改后 w 并没有被修改。

b[0]=3 将会使 x 修改,因为两者 data 都指向同一个内存地址。(但是要注意,这是值拷贝,如果添加元素过多,会导致 b 的 data 指针使用新的内存地址而 x 还是指向原来的)

copy(c, b) 函数不会因为切片大小不同出错,会尽可能把 b 切片中的元素拷贝到 c 中。


我们可以对数组切片如 z := a[0:2] z 将是一个切片,指向 a 的前两个元素,go 会自动提供数组来保存。


Map

image-20220402050751005

假设要计算一个文件中不同单词出现的次数,就可以使用 Maps。是一个 Hash table。

m 是一个描述符,但是整体为空。 p 的 data 指针指向一个哈希表。


image-20220402051658526

map 与 map 间不能进行比较,只能进行 nil 比较。

可以查看 map 的长度,不能查看 map 的容量。


image-20220402051820579

可以通过获取第二个参数判断键值对是否存在。


Built in functions

image-20220402052141191

Make nil useful

image-20220402052630469

由于 len、cap、range 这些内建函数是安全的,我们不需要 if 判断 nil 就可以直接使用。

range 将会跳过 nil、empty 的循环对象。


Quote

image-20220402053526148

一种不影响你思考编程的方式的语言是不值得了解的


Practice

编写一个段落单词计数器,输出前三个出现次数最多的单词。

main.go

package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
)

func main() {
	scan := bufio.NewScanner(os.Stdin)
	words := make(map[string]int)

	// ^ 默认是按行读取,所以手动指定按单词读取
	scan.Split(bufio.ScanWords)

	for scan.Scan() {
		words[scan.Text()]++
	}

	fmt.Println(len(words), "unique words")

	type kv struct {
		key string
		val int
	}

	var ss []kv

	for k, v := range words {
		ss = append(ss, kv{k, v})
	}

	// ^ 直接修改原切片
	sort.Slice(ss, func(i, j int) bool {
		return ss[i].val > ss[j].val
	})

	for _, s := range ss[:3] {
		fmt.Println(s.key, "appears", s.val, "times")
	}
}

scan.Split(bufio.ScanWords) Scanner 默认是按行读取,所以手动指定按单词读取。

kv{k, v} 结构体的初始化

sort.Slice 函数直接修改原切片,传入的函数在 return 前面的元素排在切片的前面。如左>右,则大的元素在切片最前面,属于降序排序。


test.txt

matt went to greece
where did matt go
alan went to rome
matt didn't go there

第一行是空行是有原因的,这是 BOM头(Byte Order Mark) 导致的,具体请看另一篇文章

重定向管道流读取TXT文本第一次读取为""空字符串 - 小能日记 - 博客园 (cnblogs.com)


result

cat test.txt | go run .

12 unique words
matt appears 3 times
to appears 2 times
go appears 2 times
posted @ 2022-04-02 08:23  小能日记  阅读(22)  评论(0编辑  收藏  举报