本篇是「对比 Python 学习 Go」[1] 系列的第四篇,本篇文章我们来看下 Go 的高级数据结构,因文章偏长分为两篇,此为上篇。本系列的其他文章可到 「对比 Python 学习 Go」- 开篇[2] 查看,下面我们开始今天的分享。
Python 数据结构底层完全依赖解释器的实现方式,没有特殊说明文中数据结构对应默认解释器 CPython。
从数据结构上来讲,有「数组」和「链表」两种基本的数据结构,还有很多基于他们的高级数据结构如栈、队列、散列表等等。作为编程语言,Go 和 Python 是如何定义自己的数据结构的呢?根据数据结构的特性,我们大致可以将 Go 和 Python 的数据结构分如下几个类型:
- 「类数组的结构」,具有数组的一些特性,但不完全是数组。
- 「哈希类型」,即 key-value 类型或叫 map 类型。
- 语言自己特有的一些高级结构。
下边我们来逐一介绍。
类数组结构
数组,它是一个线性表的结构。它有如下特性:
- 使用一组连续的内存空间来存储数据。
- 存储的数据具有相同类型。
回顾了数组的特性,我们来看下 Go 和 Python 中有哪些类数组的数据结构。
Go
在 Go 语言中,有「数组」和「切片」两个类数组数据结构。
数组
Go 的数组特性可总结如下:
- 固定长度:这意味着数组不可增长、不可缩减。想要扩展数组,只能创建新数组,将原数组的元素复制到新数组。
- 内存连续:这意味着可以通过下标的方式(arr[index])索引数组中的元素。
- 固定类型:固定类型意味着限制了每个数组元素可以存放什么样的数据,以及每个元素可以存放多少字节的数据。
数组的初始化和操作如下:
package main
import "fmt"
func main() {
// 类型 [n]T是一个有 n个类型为 T的值的数组
// 先声明,后赋值
var a [2]string
a[0] = "Hello"
a[1] = "World"
// 声明时,直接赋值
b := [5]int{
10,20,30,40,50}
// 可直接通过下标来访问数组
fmt.Println(a)
fmt.Println(a[0], a[1])
fmt.Println(b)
fmt.Println(b[1], b[2])
// 通过len()函数可获取数组长度
fmt.Println(len(a))
fmt.Println(len(b))
// 数组元素赋值
b[1] = 25
fmt.Println(b)
fmt.Println(b[1])
}
除了普通数组之外,还有多维数组,即数组的数组。
// 声明一个二维整型数组,两个维度分别存储 4 个元素和 2 个元素
var arr [4][2]int
arr[0] = [2]int{
10, 11}
arr[0][1] = 15
// 声明时,直接赋值
arr1 := [4][2]int{
{10, 11}, {20, 21}, {30, 31}, {40, 41}}
// 声明时,使用下标赋值
arr2 := [4][2]int{
1: {
20, 21}, 3: {
40, 41}}
arr3 := [4][2]int{
1: {
0: 20}, 3: {
1: 41}}
// 使用数组类初始化数组
var arr4 [2]int = arr1[1]
// 使用数组元素来赋值普通元素
var value int = arr1[1][0]
// 使用索引获取数组值
fmt.Println(arr)
fmt.Println(arr1)
fmt.Println(arr1[0][1])
fmt.Println(arr2)
fmt.Println(arr3)
fmt.Println(arr4)
fmt.Println(value)
// [[10 15] [0 0] [0 0] [0 0]]
// [10 15]
// [[10 11] [20 21] [30 31] [40 41]]
// 11
// [[0 0] [20 21] [0 0