数据类型
Go语言内置以下这些类型:
表3-1 Go语言支持的数据类型
基础类型 | 关键字 | 复合类型 |
布尔类型 | bool | 指针(pointer) |
整形 | int8、byte、int16、unit、uintptr | 数组(array) |
浮点类型 | float32、float64 | 切片(slice) |
复数类型 | complex64、complex128 | 字典(map) |
字符串 | string | 通道(chan) |
字符类型 | rune | 结构体(struct) |
错误类型 | error | 接口(interface) |
1 布尔类型
布尔类型不能接受其他类型的赋值,不支持自动或强制的类型转换。以下是bool类型的用法示例:
表3-2 bool类型的使用示例
正确用法 | 错误用法 |
var b bool b = (1!=0) fmt.Println("Result:",b) //打印结果为Result:true | var b bool b = 1 //错误编译 b = bool(1) //错误编译 |
2 整形
整形是所有编程语言里最基础的数据类型。Go语言支持的整形类型如下表所示:
表3-3 Go语言支持的整形类型
类型 | 长度(字节) | 值范围 |
int8 | 1 | -128 ~ 127 |
uint8(即byte) | 1 | 0 ~ 225 |
int16 | 2 | -32 768 ~ 32 767 |
uint16 | 2 | 0 ~ 65 535 |
int32 | 4 | -2 147 483 648 ~ 2 147 483 647 |
uint32 | 4 | 0 ~ 4 294 967 295 |
int64 | 8 | -9 223 372 036 854 775 808 ~ 9 223 372 036 854 775 807 |
int | 平台相关 | 平台相关 |
uint | 平台相关 | 平台相关 |
uintptr | 同指针 | 在32位平台下为4字节,64位平台下为8字节 |
2.1 类型表示
int和int32在Go语言里被认为是两种不同的类型,编译器不会自动做类型转换,使用强制类型转换可以解决这个问题,但要注意数据损失和溢出的问题(在这里不做具体分析),样例如下:
表3-4 int类型表示用法
正确用法 | 错误用法 |
var v1 int32 v2 := 64 v1 = int32(v2) //编译正确 | var v1 int32 v2 := 64 v1 = v2 //编译错误 |
2.2 数值运算
表3-5 Go语言支持的数值运算
符号 | 功能 | 例子 |
+ | 加法运算 | 6 + 3 = 9 |
- | 减法运算 | 6 - 3 = 3 |
* | 乘法运算 | 6 * 3 = 18 |
/ | 除法运算 | 6 / 3 = 2 |
% | 取余运算 | 6 % 3 = 0 |
2.3 比较运算
Go语言支持以下的几种比较运算符:>、<、==、>=、<=和!=。和大多数其他编程语言相同,在这里就不做具体说明了。(需要注意的是不同类型的整形数不能直接比较,但可以直接与字面常量进行比较)
2.4 位运算
Go语言支持表3-6所示的运算符。
表3-6 Go语言支持的运算符
运算 | 含义 | 样例 |
x << y | 左移 | 124 << 2 //结果为496 |
x >> y | 右移 | 124 >> 2 //结果为31 |
x ^ y | 异或 | 124 ^ 2 //结果为126 |
x & y | 与 | 124 & 2 //结果为0 |
x | y | 或 | 124 | 2 //结果为126 |
^x | 取反 | ^124 //结果为-125 |
3 浮点型
浮点型用于表示包含小数点的数据,比如1.234就是一个浮点型数据。Go语言中的浮点类型采用IEEE-754标准的表达方式。
3.1 浮点数表示
Go语言定义了两个类型float32和float64,分别等价于C语言的float类型和double类型,样例如下:
var fvalue1 float 32
fvalue1 = 12
fvalue2 := 12.0 //如果不加小数点,fvalue2会被推导为整形
fvalue3 := float32(fvalue2) //必须使用强制类型转换,直接赋值将导致编译错误
3.2 浮点数比较
因为浮点数不是一种精确的表达方式,所以直接使用“==”来判断两个浮点数是否相等会导致不稳定的结果。下面是一种推荐的替代方案:
4 复数类型
复数实际上由两个实数(在计算机中用浮点数表示)构成,一个表示实部(real),一个表示虚部(imag)。样例如下:
package main //必须有一个main包
import "fmt"
func main() {
var cvalue1 complex128 //声明
cvalue1 = 2.1 + 3.14i //赋值
fmt.Println("cvalue1 = ", cvalue1 )
//自动推导类型
cvalue2 := 3.3 + 4.4i
fmt.Printf("cvalue2 type is %T\n", cvalue2)
//通过内建函数,取实部和虚部
fmt.Println("real(cvalue2) = ", real(cvalue2), ", imag(cvalue2) = ", imag(cvalue2))
}
5 字符串
在Go语言中,字符串也是一种基本类型。相比之下,C/C++语言并不存在原生的字符串类型,通常使用字符数组来表示,并以字符指针来传递。字符串的声明和使用的样例如下:
package main
import "fmt"
func main() {
var str string
str = "Hello world"
fmt.Println(str)
}
字符串的内容可以用类似于数组下标的方式获取,但与数组不同,字符串的内容不能在初始化后被修改。
5.1 字符串操作
平时常用的字符串操作如表3-7所示。
表3-7 字符串操作方法对照表
运算 | 含义 | 样例 |
x + y | 字符串连接 | "Hello" + "World" // 结果为HelloWorld |
len(str) | 字符串长度 | len("HelloWorld") // 结果为10 |
s[i] | 取字符 | "HelloWorld"[1] // 结果为'e' |
5.2 字符串遍历
Go语言支持两种方式遍历字符串,样例如下表所示:
表3-8 字符串变量方法表
字节数组遍历 | Unicode字节遍历 |
package main
import "fmt"
func main() { str := "Hello,世界" n := len(str) for i := 0 ; i < n ; i++ { fmt.Println(i, str[i]) } } /* 运行结果 0 72 1 101 2 108 3 108 4 111 5 44 6 228 7 184 8 150 9 231 10 149 11 140 */ | package main
import "fmt"
func main() { str := "Hello,世界" for i , ch := range str{ fmt.Println(i, ch) } }
/* 运行结果 0 72 1 101 2 108 3 108 4 111 5 44 6 19990 9 30028 */ |
6 字符类型
在Go语言中支持两种字符类型,一个是byte(实际上是unit8的别名),代表UTF-8字符串的单个字节的值;另一个是rune,代表单个Unicode字符。
7 数组
数组是Go语言编程中最常用的数据结构之一。顾名思义,数组就是指一系列同一类型数据的集合。数组中包含的每个数据被称为数组元素(element),一个数组包含的元素个数被称为数组的长度。以下为一些常规的数组声明方法:
var b [32]byte //长度为32的数组,每个元素为一个字节
var s [32] struct{x,y int} //复杂类型数组
var f1 [32] *float64 //指针数组
var f2 [2][4][4] float64 //等同于[2]([2]([2] float64))
var i [4][8] int //二维数组
8 数组切片
数组的长度在定义之后无法再次修改;数组是值类型,每次传递都将产生一份副本。这些都是数组的特点,但这种数据结构无法完全满足开发者的真实需求。Go语言提供了数组切片(slice)这种数据类型来弥补数组的不足。
数字切片就像一个指向数组的指针,数组切片的数据结构可以抽象为以下3个变量:
- 一个指向原生数组的指针;
- 数组切片中的元素个数;
- 数组切片已分配的存储空间。
8.1 创建数组切片
创建数组切片的方法如下表所示:
基于数组 |
package main
import "fmt"
func main() { //定义数组 var array [10]int = [10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
//基于前五个数组元素创建一个切片 var slice []int = array[:5] //从第五个数组元素创建一个切片 array[5:] //数组转为切片 array[:] fmt.Println("Array:") for _, v := range array { fmt.Print(v, " ") } fmt.Println("") fmt.Println("Slice:") for _, v := range slice { fmt.Print(v, " ") } } //运行结果为: //Array: //0 1 2 3 4 5 6 7 8 9 //Slice: //0 1 2 3 4 |
直接创建 |
package main
import "fmt"
func main() { //使用make()直接创建数组切片 //创建一个初始元素个数为5的数组切片,元素初始值为0 slice1 := make([]int, 5) fmt.Println(len(slice1)) //创建一个初始元素个数为5的数组切片,元素初始值为0,并预留10个元素的存储空间 slice2 := make([]int, 5, 10) fmt.Println(len(slice2)) //直接创建并初始化包含5个元素的数组切片 slice3 := []int{0, 1, 2, 3, 4} fmt.Println(len(slice3)) } //运行结果为: //5 //5 //5 |
8.2 切片常用的方法
8.2.1 遍历
操作数组元素的所有方法都适用于数组切片,比如数组切片也可以按下标读写元素,用len()函数获取元素的个数,并支持使用range关键字来快速遍历所有元素。
传统的元素遍历如下:
slice := []int{1, 2, 3, 4, 5}
for i := 0; i < len(slice ); i++ {
fmt.Print(slice [i], " ")
}
使用range关键字可以让遍历代码显得更整洁。range表达式有两个返回值,第一个是索引,第二个是元素的值,代码如下:
slice := []int{1, 2, 3, 4, 5}
for i, v := range slice {
fmt.Println("d[", i, "]=", v)
}
8.2.2 增减元素
使用append()操作切片,代码如下:
package main
import "fmt"
func main() {
a := []int{1, 2, 3, 4, 5}
fmt.Println("a =", a, "len=", len(a))
d := make([]int, 0)
//添加切片a的前2个元素,添加切片a下标从3开始之后的元素
//总结一下:冒号在前是个数;冒号在后是下标,保留的是冒号没有数字的一侧
//只有(int):和:(int)的用法。
//添加一个切片要用...展开运算符
d = append(a[:2], a[3:]...)
fmt.Println("d =", d, "len=", len(d))
}
//删除切片中的第三个元素
//打印结果如下:
//a = [1 2 3 4 5] len= 5
//d = [1 2 4 5] len= 4
8.2.3 扩容
package main
import "fmt"
func main() {
a := make([]int, 0)
fmt.Printf("当前切片的长度:%d,容量:%d\n", len(a), cap(a))
for i := 0; i < 10; i++ {
a = append(a, i)
fmt.Printf("当前切片的长度:%d,容量:%d\n", len(a), cap(a))
}
}
//打印结果如下:
//当前切片的长度:0,容量:0
//当前切片的长度:1,容量:1
//当前切片的长度:2,容量:2
//当前切片的长度:3,容量:4
//当前切片的长度:4,容量:4
//当前切片的长度:5,容量:8
//当前切片的长度:6,容量:8
//当前切片的长度:7,容量:8
//当前切片的长度:8,容量:8
//在添加元素之前判断切片是否有剩余,如果没有剩余且容量小于1024,成倍增加容量
//在没有添加元素之前的容量是8,所以扩容量为8
//当前切片的长度:9,容量:16
//当前切片的长度:10,容量:16
- 如果容量小于1024的时候,是成倍数的添加容量
- 如果容量大于1024的时候,是之前的1/4的来添加容量
9 map
Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。
Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,我们无法决定它的返回顺序,这是因为 Map 是使用 hash 表来实现的。
9.1 map的常见用法
package main
import "fmt"
type StudentInfo struct {
Name string
ClassRoom string
}
func main() {
var students map[int]StudentInfo
students = make(map[int]StudentInfo)
//添加元素
students[0] = StudentInfo{"小明", "三年级(1)班"}
students[1] = StudentInfo{"小红", "三年级(1)班"}
students[2] = StudentInfo{"小李", "三年级(2)班"}
students[3] = StudentInfo{"小王", "三年级(2)班"}
students[4] = StudentInfo{"小赵", "三年级(3)班"}
//遍历元素
fmt.Println("学生信息如下:")
for _, student := range students {
fmt.Println(student)
}
//查找元素
stua, ok := students[3]
if ok {
fmt.Println("下标是3的学生信息:", stua)
} else {
fmt.Println("查找失败!")
}
//删除元素
delete(students, 1)
fmt.Println("新的学生信息如下:")
for _, student := range students {
fmt.Println(student)
}
//修改元素
stub, ok := students[2]
if ok {
stub.ClassRoom = "三年级(3)班"
} else {
fmt.Println("查找失败!")
}
fmt.Println("修改后的学生信息:", stub)
}
参考:
- 总结go语言中切片的使用_水痕01的博客-CSDN博客_go语言切片的三种方法
- Go 切片详解(理解是关键) | Go 技术论坛 (learnku.com)
- Go 语言Map(集合) | 菜鸟教程 (runoob.com)
原文链接:Go学习笔记(篇三)数据类型