这篇文章主要介绍“Go语言容器的数组和切片如何使用”,在日常操作中,相信很多人在Go语言容器的数组和切片如何使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Go语言容器的数组和切片如何使用”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
序列容器
序列容器存储特定类型的数据元素。目前有 5 种序列容器的实现:
array
vector
deque
list
forward_list
这些序列容易可以用顺序的方式保存数据,利用这些序列容易能够编写有效的代码,重复使用标准库的模块化。
数组
Go 语言中的数组类型有点类似 C++ 中的数据,Go 的数组初始化定义后,在编译时就不会再变更。
定义数组的方式如下:
var a [10]int b := [5]string {"H", "e", "l", "l", "o"}
[n]T类型就表示含有
n个类型为
T的数组,本例中就是 a 变量表示含有 10 个 int 类型的整型数组;b 变量表示含有 5 个 string 类型的字符串数组。 数组的长度作为其类型的一部分,因此数组的长度是无法调整的。
package main import "fmt" func main() { var a [10]int a[0] = 2022 a[1] = 2023 fmt.Println(a[0], a[1]) fmt.Println(a) b := [5]string {"H", "e", "l", "l", "o"} fmt.Println(b) }
运行结果如下:
Vector
你可能会好奇,Go 语言又没有 C++ 中的 Vector 类型,为什么会举出这个例子。
其实 Go 最初有一个 Vector 类型的实现,但在 2011 年 10 月 11 日,在 Go 语言的开发阶段被删除了。保留了现在的切片,而切片就变成了实际上更好的 Vector 实现。
一个数组有固定的大小,但切片是一个动态、灵活的数组元素的视图,在实际中,切片比数组更为常见。
[]T表示是一个具有类型
T的元素切片,
[]byte是 byte slice,指元素为 byte 的 slice;
[]string是 string slice,指元素为 string 的 slice。
切片通过指定两个切点
a[low : high],可以定义如下的
sliceExample切片:
sliceExample := []string{"Say", "Hello", "to", "you"}
切片对比数组的最大优点就是:可以随着增加和删除来增加或减少容器的大小。我们来看一个例子:
package main import "fmt" // remove i indexed item in a slice func remove(s []string, i int) []string { copy(s[i:], s[i+1:]) return s[:len(s)-1] } func main() { primes := [6]int{2, 3, 5, 7, 11, 13} var s []int = primes[1:4] fmt.Println(s) sliceExample := []string{"Say", "Hello", "to", "you"} sliceExample = append(sliceExample, ",My Gopher Friends~") fmt.Println("Append Slice: ", sliceExample) sliceExample = remove(sliceExample, 0) fmt.Println("After Removed Item: ", sliceExample) }
运行结果如下图:
我们分享了 Go 语言提供的容器中的数组和切片,不管是数据还是切片,它们内部的数据类型必须是一致的(要么都是整型、要么都是字符串类型)。但数据的大小是固定,而切片可以根据元素的添加和减少动态调整容器大小。
Deque
Deque,即双端队列,是一个可以扩展的容器。扩展可以发生在容器的前面或后面。当队列的顶部或尾部需要经常被引用时,经常使用双端队列。
下面的代码块显示了 Go 双端队列 deque 的使用:
package main import ( "fmt" "github.com/gammazero/deque" ) func main() { var q deque.Deque[string] q.PushBack("I") q.PushBack("love") q.PushBack("learning") q.PushBack("Go") fmt.Println("队列长度为: ", q.Len()) // Prints: 4 fmt.Println("队首为元素:", q.Front()) // Prints: I fmt.Println("队尾为元素: ", q.Back()) // Prints: Go q.PopFront() // remove "I" q.PopBack() // remove "Go" q.PushFront("Hello") q.PushBack("World") // Consume deque and print elements. for q.Len() != 0 { fmt.Println(q.PopFront()) } }
运行结果如图:
List
List 在 Go 语言中有一个双链表的实现,它位于内置标准库
container/list包中
我们可以直接使用这个链表的实现:
package main import ( "container/list" "fmt" ) func main() { // Create a new list and put some numbers in it. l1 := list.New() e4 := l1.PushBack(4) e1 := l1.PushFront(1) l1.InsertBefore(3, e4) l1.InsertAfter(2, e1) // now l1 is [1 2 3 4] // Iterate through list and print its contents. for e := l1.Front(); e != nil; e = e.Next() { fmt.Println(e.Value) } l1.MoveToBack(e1) // now l1 is [4 2 3 1] listLength := l1.Len() // length is 4 fmt.Printf("l1 type: %T ", l1) fmt.Println("l1 length : :", listLength) for e := l1.Front(); e != nil; e = e.Next() { fmt.Println(e.Value) } }
运行结果为:
1
2
3
4
l1 type: *list.List
l1 length : : 4
2
3
4
1
单链表
最后介绍一下单链表,如果我们想实现的数据结构并没有标准的容器集成,此时我们就可以通过自己根据要求来写一个自己想要的容器类型,这里以头插法的单链表举例:
package main import "fmt" type SinglyLinkedList struct { head *LinkedListNode } type LinkedListNode struct { data string next *LinkedListNode } func (ll *SinglyLinkedList) Append(node *LinkedListNode) { if ll.head == nil { ll.head = node return } currentNode := ll.head for currentNode.next != nil { currentNode = currentNode.next } currentNode.next = node } func main() { ll := &SinglyLinkedList{} ll.Append(&LinkedListNode{data: "Hello"}) ll.Append(&LinkedListNode{data: "Gopher"}) for e := ll.head; e != nil; e = e.next { fmt.Println(e.data) } }
运行结果如图: