最近学习:《The Way to Go》,中文名《Go 入门指南》记录下学习轨迹
一、slice
声明+初始化: var s []int = arr[start:end]
s := []int{1,2,3}
slice=完整array
(1)slice1 := arr1[:] //arr1[0:len(arr1)]的缩写
(2)slice1 = &arr1
s == s[:i] + s[i:] // i是整数且0<=i<=len
arr1[3:] == arr1[3:len(arr1)]
arr1[:3] == arr1[0:3] //从第一个到第三个元素(不包括第四个)
去掉slice1的最后一个元素,slice1 = slice1[:len(slice1)-1]
slice2向后移动一位,slice2 = slice2[1:]
//注意:s2 = s2[-1:] 会导致编译错误,末尾不能移动。切片不能被重新分片以获取数组的前一个元素。
绝对不要用指针指向slice。切片已经是一个引用类型,所以它本身就是一个指针
//注意:slice,map,channel都是指针
生成切片(len=50,cap=100):
slice1 := make([]int, 50, 100)
slice2 := new([100]int)[0:50]
new() 和 make() 的区别:
(1)new(T)返回一个指向(类型为T,值为0的)地址的指针
make(T)返回一个类型为T的初始值
(2)new(T)适用于值类型如:array和struct。相当于 &T{}
make(T)只适用于3种内建的引用类型:map、slice、channel
(3)new(T)获取内存地址:获取的是存储指定变量内存地址的一个变量,对于变量内部结构并不会执行相应的初始化操作
make(T)初始化并获取对应的内存地址:
slice的len(长度)和cap(容量)的计算
len(slice) = j - i
cap(slice) = 总数 - i
package main
import "fmt"
func main() {
s := make([]byte, 5)
fmt.Println(len(s)) //5
fmt.Println(cap(s)) //5
s = s[2:4] //i=2,j=4,总数=5
fmt.Println(len(s)) //4-2=2
fmt.Println(cap(s)) //5-2=3
}
package main
import "fmt"
func main() {
s1 := []byte{'p', 'o', 'e', 'm'}
s2 := s1[2:]
fmt.Printf("s2=%+s\n", s2) //s2=em
s2[1] = 't'
fmt.Printf("s1=%+s,s2=%+s", s1, s2) //s1=poet,s2=et
}
bytes包
[]byte的切片,用bytes包专门提供它的操作方法
定义的3种方式:
(1)var buffer bytes.Buffer
(2)var r *bytes.Buffer = new(bytes.Buffer)
(3)func NewBuffer(buf []byte) *Buffer 创建一个Buffer对象并且用buf初始化好,用在从buf读取时
使用步骤如下:
var buffer bytes.Buffer //定义
buffer.WriteString(s) //塞字符串
fmt.Print(buffer.String(), "\n") //输出
给定切片 sl,将一个 []byte 数组追加到 sl 后面。写一个函数 Append(slice, data []byte) []byte,该函数在 sl 不能存储更多数据的时候自动扩容
package main
import (
"fmt"
)
func main() {
sl := []byte {'a', 'u', 'z', 's'}
data := []byte{'g', 'o', 'l', 'a', 'n', 'g'}
sliceVal := append(sl, data)
fmt.Printf("slice = %+s \n", sliceVal) //slice = auzsgolang
}
func append(slice, data []byte) []byte {
sliceLen := len(slice)
dataLen := len(data)
newLen := sliceLen + dataLen
// make新的切片时若容量大于原切片,需扩充
newCap := cap(slice)
if newLen > cap(slice) {
newCap = newLen
}
newSlice := make([]byte, newLen, newCap)
for sliceKey, sliceItem := range slice {
newSlice[sliceKey] = sliceItem
}
for dataKey, item := range data {
newSlice[dataKey + sliceLen] = item
}
return newSlice
}
把一个缓存 buf 分片成两个 切片:第一个是前 n 个 bytes,后一个是剩余的,用一行代码实现。
package main
import (
"bytes"
"fmt"
)
func main() {
n := 4
str := "hello,go!"
var buffer bytes.Buffer
buffer.WriteString(str)
bPrefix, bSuffix := buffer.Bytes()[:n], buffer.Bytes()[n:]
fmt.Printf("bPrefix=%s,bSuffix=%s\n", string(bPrefix), string(bSuffix))
//bPrefix=hell,bSuffix=o,go!
}
如果a是一个切片,a[n:n]长度是多少?a[n:n+1] 的长度又是多少?
a[n:n]=[], len(a[n:n]) =0 其中,0<=n<=cap,超过就报错
a[n:n+1]=a[n],len(a[n:n+1])=1 其中,0<=n<cap,超过就报错
package main
import "fmt"
func main() {
slFrom := []int{1, 2, 3}
slTo := make([]int, 10)
n := copy(slTo, slFrom)
fmt.Println(slTo)//[1 2 3 0 0 0 0 0 0 0]
fmt.Printf("Copied %d elements\n", n) // n == 3
sl3 := []int{1, 2, 3}
sl3 = append(sl3, 4, 5, 6)
fmt.Println(sl3)//[1 2 3 4 5 6]
}
//append在大多数情况下很好用,但是想完全掌控整个追加过程,要实现AppendByte
func AppendByte(slice []byte, data ...byte) []byte {
m := len(slice)
n := m + len(data)
if n > cap(slice) { // if necessary, reallocate
// allocate double what's needed, for future growth.
newSlice := make([]byte, (n+1)*2)
copy(newSlice, slice)
slice = newSlice
}
slice = slice[0:n]
copy(slice[m:n], data)
return slice
}
练习 7.9
练习 7.10
//InsertStringSlice 将切片插入到另一个切片的指定位置
package main
import "fmt"
func main() {
src := []string{"a", "b", "c", "d", "e"}
newstr := []string{"f", "g"}
fmt.Println(insertSlice(2, newstr, src))
}
func insertSlice(index int, newstr []string, src []string) (ns []string) {
ns = append(ns, src[:index]...) // 切片后加..., 相当于拆包成单个元素
ns = append(ns, newstr...)
ns = append(ns, src[index:]...)
return
}
/* [a b f g c d e] */
// remove sub slice
package main
import "fmt"
func main() {
s := []int{0, 1,2,3,4,5,6,7,8,9}
fmt.Println(removeSub(s, 3, 7))
}
func removeSub(s []int, start int, end int) (ns []int) {
for ix, num := range s {
if start <= ix && ix < end {
continue
}
ns = append(ns, num)
}
return
}
/* [0 1 2 8 9] */
二、map
声明: var mp1 map[string]int
初始化: mp1 := map[string]int{"one":1, "two":2}
不要使用new,永远用make来构造map
map的返回值可以是任意的,可以用切片作为map的值,mp2 := make(map[int]*[]int)
//如果key1存在则ok == true,否则ok为false
if _, ok := map1[key1]; ok {
}
//从map1中删除key1
delete(map1, key1)
package main
import "fmt"
func main() {
map1 := make(map[int]float32)
map1[1] = 1.0
map1[2] = 2.0
map1[3] = 3.0
map1[4] = 4.0
for key, value := range map1 {
fmt.Printf("key is: %d - value is: %f\n", key, value)
}
}
/*key is: 3 - value is: 3.000000
key is: 1 - value is: 1.000000
key is: 4 - value is: 4.000000
key is: 2 - value is: 2.000000*/
注意map本质是散列表。不是按照key或valule的顺序排列。
map类型的切片
package main
import "fmt"
func main() {
// Version A:
items := make([]map[int]int, 5)
for i:= range items {
items[i] = make(map[int]int, 1)
items[i][1] = 2
}
fmt.Printf("Version A: Value of items: %v\n", items)
// Version B: NOT GOOD!
items2 := make([]map[int]int, 5)
for _, item := range items2 {
item = make(map[int]int, 1) // item is only a copy of the slice element.
item[1] = 2 // This 'item' will be lost on the next iteration.
}
fmt.Printf("Version B: Value of items: %v\n", items2)
}
/*Version A: Value of items: [map[1:2] map[1:2] map[1:2] map[1:2] map[1:2]]
Version B: Value of items: [map[] map[] map[] map[] map[]]*/
注意:应当像A版本那样通过索引使用切片的map元素。在B版本中获得的项只是map值的一个拷贝而已,所以真正的map元素没有得到初始化。
map的排序
将key或value拷贝到一个切片,再对切片排序,最后使用切片的for-range方法。
package main
import (
"fmt"
"sort"
)
var (
barVal = map[string]int{"hotel": 16, "alpha": 34, "kili": 43, "indio": 87,"juliet": 65,"lima": 98}
)
func main() {
fmt.Print("unsorted:")
i := 0
keys := make([]string, len(barVal))
for k, v := range barVal {
fmt.Printf("K=%v,V=%v; ", k, v)
keys[i] = k
i++
}
sort.Strings(keys)
fmt.Println()
fmt.Print("sorted:")
for _, k := range keys {
fmt.Printf("K=%v,V=%v; ", k, barVal[k])
}
}
/*unsorted:K=hotel,V=16; K=alpha,V=34; K=kili,V=43; K=indio,V=87; K=juliet,V=65; K=lima,V=98;
sorted:K=alpha,V=34; K=hotel,V=16; K=indio,V=87; K=juliet,V=65; K=kili,V=43; K=lima,V=98;*/
三、struct
type struct1 struct {
i1 int
f1 float32
str string
}
【声明】
t := new(struct1) //等价 var t *struct1 加 t = new(struct1)
【声明+初始化】
ms := &struct1{10, 15.5, "Chris"}
等价于:
var ms struct1
ms = struct1{10, 15.5, "Chris"}
等价于:
ms := new(struct1)
ms.i1 = 10
ms.f1 = 15.5
ms.str= "Chris"
注意:值的顺序必须按照定义顺序赋值