这里记录了假期时看到的一些代码片段以及知识点,觉得不错就记录了下来。
map
Go 实现 map 排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package main import ( "sort" "fmt" ) func map_sort(ages map[string]int) { var names []string for name := range ages { names = append(names, name) } sort.Strings(names) for _, name := range names { fmt.Printf("%s\t%d\n", name, ages[name]) } }
|
要判断两个 map 是否包含相同的 key 和 value,我们必须通过一个循环实现:
1 2 3 4 5 6 7 8 9 10 11
| func equal(x, y map[string]int) bool { if len(x) != len(y) { return false } for k, xv := range x { if yv, ok := y[k]; !ok || yv != xv { return false } } return true }
|
Reader 接口
Reader 接口的定义如下:
1 2 3
| type Reader interface { Read(p []byte) (n int, err error) }
|
官方文档中关于该接口方法的说明:
也就是说,当 Read 方法返回错误时,不代表没有读取到任何数据。调用者应该处理返回的任何数据,之后才处理可能的错误。
Writer 接口
Writer 接口的定义如下:
1 2 3
| type Writer interface { Write(p []byte) (n int, err error) }
|
官方文档中关于该接口方法的说明:
同样的,所有实现了 Write 方法的类型都实现了 io.Writer 接口。
实现了 io.Reade r接口或 io.Writer 接口的类型
我们可以知道,os.File 同时实现了这两个接口。我们还看到 os.Stdin/Stdout 这样的代码,它们似乎分别实现了 io.Reader/io.Writer 接口。没错,实际上在 os 包中有这样的代码:
1 2 3 4 5
| var ( Stdin = NewFile(uintptr(syscall.Stdin), "/dev/stdin") Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout") Stderr = NewFile(uintptr(syscall.Stderr), "/dev/stderr") )
|
也就是说,Stdin/Stdout/Stderr 只是三个特殊的文件(即都是 os.File 的实例),自然也实现了 io.Reader 和io.Writer。
目前,Go 文档中还没法直接列出实现了某个接口的所有类型。不过,我们可以通过查看标准库文档,列出实现了io.Reader 或 io.Writer 接口的类型(导出的类型):
1 2 3 4 5 6 7 8 9 10
| - os.File 同时实现了io.Reader和io.Writer - strings.Reader 实现了io.Reader - bufio.Reader/Writer 分别实现了io.Reader和io.Writer - bytes.Buffer 同时实现了io.Reader和io.Writer - bytes.Reader 实现了io.Reader - compress/gzip.Reader/Writer 分别实现了io.Reader和io.Writer - crypto/cipher.StreamReader/StreamWriter 分别实现了io.Reader和io.Writer - crypto/tls.Conn 同时实现了io.Reader和io.Writer - encoding/csv.Reader/Writer 分别实现了io.Reader和io.Writer - mime/multipart.Part 实现了io.Reader
|
除此之外,io 包本身也有这两个接口的实现类型。如:
实现了Reader 的类型:LimitedReader、PipeReader、SectionReader
实现了 Writer 的类型:PipeWriter
以上类型中,常用的类型有:os.File、strings.Reader、bufio.Reader/Writer、bytes.Buffer、bytes.Reader。
切片
切片可以看作是对数组的一种包装形式,它所包装的数组称为该切片的底层数组。换句话说,切片是针对其底层数组中某个连续片段的描述符。
一个切片值总会持有一个对某个数组值的引用,事实上,一个切片值一旦被初始化,就会与一个包含了其中元素值的数组值相关联,即底层数组。多个切片值可能会共同用同一个底层数组。例如,如果把一个切片值复制成多个,或者针对其中的某个连续片段再切片成新的切片值,那么这些切片值所引用的都会是同一个底层数组。对切片值中的元素值的修改,实质上就是对底层数组上的对应元素的修改。从这个角度看,切片类似于指向底层数组的指针。反过来讲,对作为底层数组中元素值的改变,也会体现到引用该底层数组且包含该元素值的所有切片值上。