网站名字备案流程新媒体营销推广方案
1. 数组
数组是一个由固定长度的特定类型元素组成的序列,一个数组可以由零个或多个元素组成。因为数组的长度是固定的,所以在Go语言中很少直接使用数组
声明语法:
var 数组变量名 [元素数量]Type
package main
import ("fmt"
)
func main() {var a [3]int // 定义三个整数的数组,仅是定义,默认值是填0fmt.Println(a[0]) // 打印第一个元素fmt.Println(a[len(a)-1]) // 打印最后一个元素// 打印索引和元素for i, v := range a {fmt.Printf("%d %d\n", i, v)}for _, v := range a {fmt.Printf("%d\n", v)}var q = [...]int{1, 2, 3}var r = [3]int{1, 2}fmt.Println(q[1]) // "2"fmt.Println(r[2]) // "0"k := [...]int{1, 2, 3}v := [...]int{2, 3, 4}//m := [...]int{1, 2, 3, 4}fmt.Println(k == v) //false//fmt.Println(k == m) //不同类型无法进行比较var teams [3]stringteams[0] = "hello"teams[1] = "go"teams[2] = "!"for i, v := range teams {fmt.Printf("序号: %d 值: %s\n", i, v)}
}
2. 切片
2.1 定义切片
// 声明字符串切片
var strList []string
// 声明整型切片
var numList []int
// 声明一个空切片
var numListEmpty = []int{}
// 输出3个切片
fmt.Println(strList, numList, numListEmpty)
// 输出3个切片大小
fmt.Println(len(strList), len(numList), len(numListEmpty))
// 切片判定空的结果
fmt.Println(strList == nil)
fmt.Println(numList == nil)
fmt.Println(numListEmpty == nil)
make构造切片
a := make([]int, 2)
b := make([]int, 2, 10)
fmt.Println(a, b)
fmt.Println(len(a), len(b))
2.2 为切片新增元素
package main
import "fmt"
var numbers []int
func main() {var a []intx := []int{1, 2, 3}a = append(a, 1) // 追加1个元素a = append(a, 1, 2, 3) // 追加多个元素, 手写解包方式a = append(a, x...) // 追加一个切片, 切片需要解包fmt.Println(a)deal()var b = []int{1, 2, 3}b = append([]int{0}, b...) // 在开头添加1个元素fmt.Println(b)b = append([]int{-3, -2, -1}, b...) // 在开头添加1个切片fmt.Println(b)
}
func deal() {for i := 0; i < 10; i++ {numbers = append(numbers, i)fmt.Printf("len: %d cap: %d pointer: %p\n", len(numbers), cap(numbers), numbers)}
}
2.3 切片复制
copy作用前面的切片元素,以小的切片元素为复制对象
package main
import "fmt"
func main() {slice1 := []int{1, 2, 3, 4, 5}slice2 := []int{5, 4, 3}copy(slice2, slice1) // 只会复制slice1的前3个元素到slice2中fmt.Println(slice1) //[1 2 3 4 5]fmt.Println(slice2) //[1 2 3]slice2 = []int{7, 8, 9}copy(slice1, slice2) // 只会复制slice2的3个元素到slice1的前3个位置fmt.Println(slice1) //[7 8 9 4 5]
}
package main
import "fmt"
func main() {// 设置元素数量为1000const elementCount = 1000// 预分配足够多的元素切片srcData := make([]int, elementCount)// 将切片赋值for i := 0; i < elementCount; i++ {srcData[i] = i}// 引用切片数据refData := srcData// 预分配足够多的元素切片copyData := make([]int, elementCount)// 将数据复制到新的切片空间中copy(copyData, srcData)// 修改原始数据的第一个元素srcData[0] = 999// 打印引用切片的第一个元素fmt.Println(refData[0])// 打印复制切片的第一个和最后一个元素fmt.Println(copyData[0], copyData[elementCount-1])// 复制原始数据从4到6(不包含)copy(copyData, srcData[4:6])for i := 0; i < 5; i++ {fmt.Printf("%d ", copyData[i])}
}
代码说明如下:
- 第 8 行,定义元素总量为 1000。
- 第 11 行,预分配拥有 1000 个元素的整型切片,这个切片将作为原始数据。
- 第 14~16 行,将 srcData 填充 0~999 的整型值。
- 第 19 行,将 refData 引用 srcData,切片不会因为等号操作进行元素的复制。
- 第 22 行,预分配与 srcData 等大(大小相等)、同类型的切片 copyData。
- 第 24 行,使用 copy() 函数将原始数据复制到 copyData 切片空间中。
- 第 27 行,修改原始数据的第一个元素为 999。
- 第 30 行,引用数据的第一个元素将会发生变化。
- 第 33 行,打印复制数据的首位数据,由于数据是复制的,因此不会发生变化。
- 第 36 行,将 srcData 的局部数据复制到 copyData 中。
- 第 38~40 行,打印复制局部数据后的 copyData 元素。
2.4 切片删除元素
2.4.1 开头元素
特性
a := []int{1, 2, 3}
a = a[1:] // 删除开头1个元素
a = a[N:] // 删除开头N个元素
append
a = []int{1, 2, 3}
a = append(a[:0], a[1:]...) // 删除开头1个元素
a = append(a[:0], a[N:]...) // 删除开头N个元素
copy
a = []int{1, 2, 3}
a = a[:copy(a, a[1:])] // 删除开头1个元素
a = a[:copy(a, a[N:])] // 删除开头N个元素
2.4.2 中间删除
a = []int{1, 2, 3, ...}
a = append(a[:i], a[i+1:]...) // 删除中间1个元素
a = append(a[:i], a[i+N:]...) // 删除中间N个元素
a = a[:i+copy(a[i:], a[i+1:])] // 删除中间1个元素
a = a[:i+copy(a[i:], a[i+N:])] // 删除中间N个元素
2.4.3 末尾删除
a := []int{1, 2, 3}
a = a[:len(a)-1] // 删除尾部1个元素
a = a[:len(a)-N] // 删除尾部N个元素
2.4.4 指定元素删除
package main
import "fmt"
func main() {list1 := []int{1, 2, 3, 3, 5, 4}list2 := []int{1, 2, 3, 3, 5, 4}list1 = DeleteSlice3(list1, 3)fmt.Println(list1)list3 := DeleteSlice2(list2, 3)fmt.Println(list3)
}
// DeleteSlice3 位移法
func DeleteSlice3(a []int, elem int) []int {j := 0for _, v := range a {if v != elem {a[j] = vfmt.Println(a)j++}}return a[:j]
}
// DeleteSlice2 拷贝法
func DeleteSlice2(a []int, elem int) []int {tmp := make([]int, 0, len(a))for _, v := range a {if v != elem {tmp = append(tmp, v)}}return tmp
}位移法输出:
[1 2 3 3 5 4]
[1 2 3 3 5 4]
[1 2 5 3 5 4]
[1 2 5 4 5 4]
[1 2 5 4]解析:把后面不等于3的元素提前,然后根据最后j的长度来返回需要取多长,同时把3元素排除拷贝法输出:
[1]
[1 2]
[1 2 5]
[1 2 5 4]
[1 2 5 4]
解析:这个就很好理解了,创建一个空的切片,值不等就添加进去
3. 映射
3.1 map概念
package main
import "fmt"
func main() {map1 := make(map[int]int)map1 = map[int]int{1: 3, 2: 4}fmt.Println(map1)for i, v := range map1 {fmt.Printf("键是: %d 值是: %d\n", i, v)}
}
3.2 遍历map
package main
import "fmt"
func main() {slice1 := make([]int, 0)slice1 = append(slice1, 1, 2, 3, 4)map1 := make(map[int]int)for i, v := range slice1 {map1[i] = v}fmt.Println(map1)
}注明:
for i, v := range 可输出键值
如果只需要键:
for i := range
如果只需要值:
for _, v := range
3.3 map转slice排序
package main
import ("fmt""sort"
)
func main() {scene := make(map[string]int)// 准备map数据scene["route"] = 66scene["brazil"] = 4scene["china"] = 960// 声明一个切片保存map数据var sceneList []string// 将map数据遍历复制到切片中for k := range scene {sceneList = append(sceneList, k)}// 对切片进行排序sort.Strings(sceneList) //对字符串进行排序// 输出fmt.Println(sceneList)
}
3.4 删除map中的元素
package main
import ("fmt"
)
func main() {scene := make(map[string]int)// 准备map数据scene["route"] = 66scene["brazil"] = 4scene["china"] = 960delete(scene, "brazil")for k, v := range scene {fmt.Println(k, v)}
}
ps: 使用字典就是用make函数重新创个新的即可,其余的交给GC回收机制
3.5 并发环境使用Map
sync.Map 有以下特性:
- 无须初始化,直接声明即可。
- sync.Map 不能使用 map 的方式进行取值和设置等操作,而是使用 sync.Map 的方法进行调用,Store 表示存储,Load 表示获取,Delete 表示删除。
- 使用 Range 配合一个回调函数进行遍历操作,通过回调函数返回内部遍历出来的值,Range 参数中回调函数的返回值在需要继续迭代遍历时,返回 true,终止迭代遍历时,返回 false。
代码演示如下:
package main
import ("fmt""sync"
)
func main() {var scene sync.Map// 将键值对保存到sync.Mapscene.Store("greece", 97)scene.Store("london", 100)scene.Store("egypt", 200)// 从sync.Map中根据键取值fmt.Println(scene.Load("london"))// 根据键删除对应的键值对scene.Delete("london")// 遍历所有sync.Map中的键值对scene.Range(func(k, v interface{}) bool {fmt.Println("iterate:", k, v)return true})
}
代码说明如下:
- 第 10 行,声明 scene,类型为 sync.Map,注意,sync.Map 不能使用 make 创建。
- 第 13~15 行,将一系列键值对保存到 sync.Map 中,sync.Map 将键和值以 interface{} 类型进行保存。
- 第 18 行,提供一个 sync.Map 的键给 scene.Load() 方法后将查询到键对应的值返回。
- 第 21 行,sync.Map 的 Delete 可以使用指定的键将对应的键值对删除。
- 第 24 行,Range() 方法可以遍历 sync.Map,遍历需要提供一个匿名函数,参数为 k、v,类型为 interface{},每次 Range() 在遍历一个元素时,都会调用这个匿名函数把结果返回。
4. 列表
列表创建与传值
package main
import ("container/list""fmt"
)
func main() {l := list.New()l.PushFront("hello")l.PushBack("world")element := l.PushBack("wo")l.InsertBefore("baby", element)l.InsertAfter("aiNi", element)l.Remove(element)for i := l.Front(); i != nil; i = i.Next() {fmt.Println(i.Value)}
}
5. 空值与零值
指针、切片、映射、通道、函数和接口的零值则是 nil
5.1 nil标识符不能比较
package main
import ("fmt"
)
func main() {fmt.Println(nil==nil)
}
运行结果: 未定义操作
PS D:\code> go run .\main.go
#command-line-arguments
.\main.go:8:21: invalid operation: nil == nil (operator == not defined on nil)
5.2 nil不是关键字和保留字
以下编写是可以通过编译的,但不推荐这么做
var nil = errors.New("my god")
5.3 nil没有默认类型
package main
import ("fmt"
)
func main() {fmt.Printf("%T", nil)print(nil)
}
输出:
#command-line-arguments
.\main.go:7:8: use of untyped nil in argument to print
5.4 不同类型 nil 的指针是一样的
package main
import ("fmt"
)
func main() {var arr []intvar num *intfmt.Printf("%p\n", arr)fmt.Printf("%p", num)
}
输出:
0x0
0x0
Process finished with the exit code 0
5.5 nil是map、slice、pointer、channel、func、interface 的零值
package main
import ("fmt"
)
func main() {var m map[int]stringvar ptr *intvar c chan intvar sl []intvar f func()var i interface{}fmt.Printf("%#v\n", m)fmt.Printf("%#v\n", ptr)fmt.Printf("%#v\n", c)fmt.Printf("%#v\n", sl)fmt.Printf("%#v\n", f)fmt.Printf("%#v\n", i)
}
输出:
PS D:\code> go run .\main.go
map[int]string(nil)
(*int)(nil)
(chan int)(nil)
[]int(nil)
(func())(nil)
5.6 不同类型的nil值占用的内存大小可能不一样
package main
import ("fmt""unsafe"
)
func main() {var p *struct{}fmt.Println( unsafe.Sizeof( p ) ) // 8var s []intfmt.Println( unsafe.Sizeof( s ) ) // 24var m map[int]boolfmt.Println( unsafe.Sizeof( m ) ) // 8var c chan stringfmt.Println( unsafe.Sizeof( c ) ) // 8var f func()fmt.Println( unsafe.Sizeof( f ) ) // 8var i interface{}fmt.Println( unsafe.Sizeof( i ) ) // 16
}
输出:
PS D:\code> go run .\main.go
8
24
8
8
8
16