三 Go的语言容器

1. 数组

数组是一个由固定长度的特定类型元素组成的序列,一个数组可以由零个或多个元素组成。因为数组的长度是固定的,所以在Go语言中很少直接使用数组

声明语法:
var 数组变量名 [元素数量]Type
package main
import (
   "fmt"
)
func main() {
    
    
   var a [3]int             // 定义三个整数的数组,仅是定义,默认值是填0
   fmt.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]string
   teams[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 []int
   x := []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() {
    
    
   // 设置元素数量为1000
   const 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 := 0
   for _, v := range a {
    
    
      if v != elem {
    
    
         a[j] = v
         fmt.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"] = 66
   scene["brazil"] = 4
   scene["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"] = 66
   scene["brazil"] = 4
   scene["china"] = 960
   delete(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.Map
    scene.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 []int
    var num *int
    fmt.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]string
    var ptr *int
    var c chan int
    var sl []int
    var 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 ) ) // 8
    var s []int
    fmt.Println( unsafe.Sizeof( s ) ) // 24
    var m map[int]bool
    fmt.Println( unsafe.Sizeof( m ) ) // 8
    var c chan string
    fmt.Println( unsafe.Sizeof( c ) ) // 8
    var f func()
    fmt.Println( unsafe.Sizeof( f ) ) // 8
    var i interface{
    
    }
    fmt.Println( unsafe.Sizeof( i ) ) // 16
}

输出:
PS D:\code> go run .\main.go
8
24
8
8
8
16

猜你喜欢

转载自blog.csdn.net/Python_BT/article/details/129433009
今日推荐