Go语言 复合数据类型数组map

Posted 谁的天空之城

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go语言 复合数据类型数组map相关的知识,希望对你有一定的参考价值。


顾名思义,复合数据类型就是由其他类型组合而成的类型。Go语言基本的复合数据类型有:指针、数组、切片、字典(map)、通道、结构和接口

一、数组(Array)

1.1 什么是数组?

Go语言提供了数组类型的数据结构。
数组是具有相同唯一类型的一组编号且长度固定的数据项序列,这种类型可以是任意的原始类型,例如:整形、字符串或者自定义类型。

数组元素可以通过索引(位置)来读取(或者修改),索引从0开始,第一个元素索引为
0,第二个索引为1,以此类推,数组的下标取值范围是从0开始,到长度减1。

1.2 数组的特点

  • 数组创建完长度就固定了,不可以再追加元素。
  • 数组是值类型的,数据赋值或作为函数参数都是值拷贝。
  • 数组长度是数组类型的组成部分,10[int]和20[int]表示不同的类型。
  • 可以根据数组创建切片。

1.3 数组的语法

数组语法:

//语法:
var variable_name[size] variable_type

var 数组名 [长度] 数据类型
var 数组名 = [长度] 数据类型{元素1,元素2...} 
数组名 := [...]数据类型{元素1...}

注:需要指明数组的大小和存储的数据类型。

示例代码:

var array [10] int //声明一个有10个整型的数组,元素默认值为0,此种方法很少使用
array := [...]float64{7.0,8.5,9.1,2.0,50.0} //[...]后面跟字面量初始化列表

初始化数组中{}中的元素个数不能大于[]中的数字。

如果忽略[]中的数字不设置数组大小,Go语言会根据元素的个数来设置数组的大小:

var array = []int {1,2,3,4,5}
arr[4] = 5

数组的其它创建方式:

array := [4]int{1,50,100,150} //指定长度和初始化字面量
array := [...]int{1,50,100,150} //不指定长度,但是由后面的初始化列表数量来确定其长度
array := [4]int{1:1,3:100} //指定总长度,并通过索引值进行初始化,没有初始化元素时,使用类型默认值

array := [...]int{1:1,3:100} //不指定总长度,通过索引值进行初始化,数组长度由最后一个索引值确定,没有指定索引的元素被初始化为类型的零值

数组访问:

  • 数组通过下标访问,也叫索引 index,可理解为:数组中存储这个元素的位置
  • 默认从0开始的整数,每次累加1,直到长度减1
  • 访问数组语法:
数组名[index]
  • 访问数组时,不能越界,取值范围为:[0,长度-1]
  • 长度和容量
len() 取数组长度,(数组中实际存储的数据量),其它还可用于array/map/slice/string
cap() 取数组容量,(数组中能够存储的数据量)

用法举例:
len(数组名) 
fmt.Println(len(数组名))

cap(数组名) 
fmt.Println(cap(数组名))

1.4 数组的内存

GO语言数组有一个16进制的首地址(内存地址)使用%p可以查看!

fmt.Printf("%p\\n", &数组名)

1.5 数组的遍历

遍历数组:

package main

import "fmt"

func main()  {
	array := [...]string{"比特币","以太坊","泰达币","SEA","门罗币"}
	for i :=0;i < len(array);i++ {
	}
	fmt.Println(array)
}

使用range遍历数组

package main

import "fmt"

func main()  {
	array := [...]string{"比特币","以太坊","泰达币","SEA","门罗币"}
	for i,v := range array{
		fmt.Printf("下标是:%v,数值是:%v\\n",i,v)
	}
}

如果只需要值并希望忽略索引,那么可以通过_blank标识符替换索引来实现这一点。

package main

import "fmt"

func main()  {
	array := [...]string{"比特币","以太坊","泰达币","SEA","门罗币"}
	for _,value := range array{
		fmt.Printf("数值是:%v\\n",value)
	}
}

1.6 数组是值类型

在 Golang 中,数组是值类型,这意味着数组也可以用在赋值操作中。变量名代表整个数组,同类型的数组可以赋值给另一个数组:

var arr1 [3]string
arr2 := [3]string{"nick", "jack", "mark"}
// 把 arr2 的赋值(其实本质上是复制)到 arr1
arr1 = arr2

复制完成后两个数组的值完全一样,但是彼此之间没有任何关系:
在这里插入图片描述
前面我们不止一次地提到:数组的类型包括数组的长度和数组元素的类型。只有这两部分都一样才是相同类型的数组,也才能够互相赋值。下面的代码中,在类型不同的数组间赋值,编译器会阻止这样的操作并报错:

// 声明第一个包含 4 个元素的字符串数组
var arr1 [4]string
// 声明第二个包含 3 个元素的字符串数组,并初始化
arr2 := [3]string{"golang", "java", "python"}
// 将 arr2 赋值给 arr1
arr1 = arr2	

编译以上代码时,会报错如下:

cannot use arr2 (type [3]string) as type [4]string in assignment
//编译器表示在赋值时不能把 type [3]string 当 type [4]string 用。

把数组赋值给其它数组时,实际上是完整地复制一个数组。所以,如果数组是一个指针型的数组,那么复制的将是指针,而不会复制指针所指向的对象。看下面的代码:

1.7 数组的排序

让数组中的元素具有一定顺序

array := [...]int{15,23,8,10,7}
	升序:	array := [...]int{7,8,10,15,23}
	降序: array := [...]int{23,15,10,8,7}

排序算法:

​ 冒泡排序、插入排序、选择排序、希尔排序、堆排序、快速排序

冒泡排序:(Bubbo Sort)

​ 依次比较两个相邻的元素,如果它们的顺序(如从小到大)就把它们的位置进行交换

示例:

func main()  {
	array := [...]int{15,23,8,10,7}
	for i := 1;i<len(array);i++  {
		for j :=0;j <len(array)-i;j++ {
			if array[j] > array[j+1]{
				array[j],array[j+1] = array[j+1],array[j]
			}
		}
		fmt.Println(array)
	}
}

1.8 多维数组

Go语言支持多维数组,以下为常用的多维数组声明语法方式:

#常用的多维数组声明方式: 
var variable_name[size] [size]...[size]variable_type

#以下实例声明了三维的整型数组:
var threedim [5][10][4]int

多维数组可通过大括号来初始值。以下 声明二维数组的示例代码 :

// 声明一个二维整型数组,两个维度分别存储 4 个元素和 2 个元素
var arr [4][2]int
// 使用数组字面量来声明并初始化一个二维整型数组
arr1 := [4][2]int{{10, 11}, {20, 21}, {30, 31}, {40, 41}}
// 声明并初始化外层数组中索引为 1 和 3 的元素
arr2 := [4][2]int{1: {20, 21}, 3: {40, 41}}
// 声明并初始化外层数组和内层数组的单个元素
arr3 := [4][2]int{1: {0: 20}, 3: {1: 41}}

下图展示了上面代码声明的二维数组在每次声明并初始化后包含的值:
在这里插入图片描述

访问二维数组

二维数组通过指定坐标来访问。如数组中的行索引与列索引,例如:  
 int val = a[2][3] 
 此示例访问了二维数组 val 第三行的第四个元素。 

1.9 总结

数组在 Golang 中是作为高性能的基础类型设计的,因此对用户来说使用起来并不是特别方便,这一点在众多的开源代码中(数组用的少,slice 用的多)可以得到印证。其实基于数组实现的 slice 以其简单灵活的特性更易于被大家接受,这也正是 Golang 设计 slice 的初衷。

数组相对于切片的特点:

  • 数组是值对象,可以进行比较,可以将数组用作 map 的映射键。而这些,切片都不可以,不能比较,无法作为 map 的映射键。
  • 数组有编译安全的检查,可以在早起就避免越界行为。切片是在运行时会出现越界的 panic,阶段不同。
  • 数组可以更好地控制内存布局,若拿切片替换,会发现不能直接在带有切片的结构中分配空间,数组可以。
  • 数组在访问单个元素时,性能比切片好。
  • 数组的长度,是类型的一部分。在特定场景下具有一定的意义。
  • 数组是切片的基础,每个数组都可以是一个切片,但并非每个切片都可以是一个数组。如果值是固定大小,可以通过使用数组来获得较小的性能提升(至少节省 slice 头占用的空间)。

1.10 数组练习题

  • 求数组[1, 3, 5, 7, 8]所有元素的和
方法一:
package main

import "fmt"

func main()  {
	arr := [5]int{1,3,5,7,8}
	sum := 0
	for i := 0;i < 5;i++{
		sum += arr[i]
	}
	fmt.Println(sum)
}


方法二:
package main

import "fmt"

func main()  {
	arr := [...]int{1,3,5,7,8}
	sum := 0
	for _,i := range arr{ //range类似迭代器,可以遍历数组,字符串,map等等
		sum += i
	}
	fmt.Println(sum)
}
  • 创建一个随机种子数并随机生成10个100以内的int类型元素,进行冒泡排序
方法1:
package main

import (
	"fmt"
	"math/rand"
	"time"
)

func main() {
	rand.Seed(time.Now().UnixNano())
	var arr [10]int
	for i := 0; i <= 9; i++ {
		num := rand.Intn(100)
		arr[i] = num
	}
	length := len(arr) - 1

	for i := length; i >= 0; i-- {
		for j := 0; j <= i - 1; j++ {
			if arr[j] > arr[j+1] {
				arr[j], arr[j+1] = arr[j+1], arr[j]
			}
		}
	} 

	fmt.Println("排序后",arr)
}


方法2:
package main

import (
	"fmt"
	"math/rand"
	"time"
)

func main()  {
	rand.Seed(time.Now().UnixNano())
	var arr [10]int
	for i := 0;i<10;i++ {
		num := rand.Intn(100)
		arr[i] = num
	}
	fmt.Println("随机数组:",arr)

	for i := 1;i <len(arr);i++{
		for j :=0;j < len(arr) - i;j++ {
			if arr[j] > arr[j+1] {
				arr[j],arr[j+1] = arr[j+1],arr[j]
			}
		}
	}
	fmt.Println("排序后数组:",arr)
}

以上是关于Go语言 复合数据类型数组map的主要内容,如果未能解决你的问题,请参考以下文章

Go Web编程实战----数据类型

Go Web编程实战----数据类型

Go Web编程实战----数据类型

[GO专栏-4]Go语言数据类型

1.3 Go微服务实战(Go语言基础) --- 字符串与复合数据类型

GO语言学习——复合数据类型 数组