Go 数据类型

基础数据类型

类型 长度(字节) 默认值 说明
bool 1 false
byte 1 0 uint8,取值范围[0,255]
rune 4 0 Unicode Code Point,int32
int,uint 4或者8 0 32位或64位操作系统
int8,uint8 1 0 -128~127,0-255
int16,uint16 2 0 -32768~32767,0-65535
int32,uint32 4 0 -21亿~21亿,0~42亿,rune是int32的别名
int64,uint64 8 0
float32 4 0.0
float64 8 0.0
complex64 8
complex128 16
uintptr 4或8 存储指定的uint32或者uint64整数

复合数据类型

类型 默认值 说明
array 取每个元素数据类型的默认值 数组,值类型
struct 取每个成员变量数据类型的默认值 类比class,值类型
string "" UTF-8字符串
slice nil 引用类型
map nil 引用类型
channel nil 引用类型
interface nil 接口
function nil 函数

数组array

数组是块连续的内存空间,在声明的时候必须指定长度,且长度不能改变。数组在声明的时候就可以把内存空间分配好,并赋默认值,即声明的时候就完成了数组的初始化。

一维数组的初始化方式

var arr1 [5]int

arr2 := [5]int{}
var arr3 = [5]int{}
var arr4 = [5]int{1, 2}                    // 给前两个元素赋值
var arr5 = [5]int{2: 30, 4: 100}      // 给指定下标的元素赋值,下标从0开始
var arr6 = [...]int{1, 2, 3, 4, 5}       // 根据元素的个数推断出数组的长度
var arr7 = [...]struct {                    // 数组的元素类型是匿名结构体
    name string
    age  int
}{{"zs", 18}, {"ls", 20}}

二维数组的初始化方式

// 指定3行2列的数组,第一行的第一列数据是1,第二列没有显式赋值默认是0
// 第二行的第一列数据是9,第二列数据是8,第三列没有显式赋值默认是0
var arr1 = [3][2]int{{1},{9,8}}
// 行的数组个数可以使用...推测,列不能使用...
var arr2 = [...][2]int {{1},{2,2},{3,3}}

访问数组的元素

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

arr1[0]                        // 通过下标的方式访问

arr1[len(arr1)-1]        // 访问最后一个元素,len函数用于获取元素的个数

var arr2 = [3][2]int{{1, 2}, {3, 4}, {5, 6}}
arr2[2][1]                        // 通过下标的方式访问二维数组

遍历数组

	// 遍历一维数组, range取得的是数组元素的拷贝
    var arr1 = [5]int{1, 2, 3, 4, 5}
	for i, data := range arr1 {
		fmt.Printf("下标= %d, 数据= %d \n", i, data)
	}
	// 遍历一维数组
    var arr1 = [5]int{1, 2, 3, 4, 5}
	for i := 0; i < len(arr1); i++ {
		fmt.Printf("下标= %d, 数据= %d \n", i, arr1[i])
	}
	// 遍历二维数组
    var arr1 = [3][2]int{{1}, {9, 8}}
	for row, array := range arr1 {
		for col, data := range array {
			fmt.Printf("第%d行 第%d列的数据是%d \n", row, col, data)
		}
	}

切片slice

  • 切片是对数组的扩展,数组的长度在定义完成后是不可变的,切片的长度是动态的,可以把切片理解成java的动态数组。切片是引用类型,自身是结构体,值拷贝传参。
  • 切片相对于数组最大的区别是可以追加元素,可以自动扩容。
  • 追加的元素放到预留的内容空间里,同时len加1
  • 如果预留空间已经用完,会重新申请一块更大的内存空间,capacity大约是之前的2倍(cap<1024)或1.25倍(cap>1024)。把原内存空间的数据拷贝到新内存上,在新内存空间上执行追加操作。

切片的源码        // 可以把 struct 理解成java中的class

type slice struct {
    array unsafe.Pointer    // 指向数组的指针
    len   int               // 切片元素个数
    cap   int               // 切片扩容量
}

切片的初始化

var s1 []int                  //len = 0,cap = 0
var s2 = []int{1, 2, 3, 4, 5} //len = 5, cap = 5
var s3 = make([]int, 3)       //len = 3,cap = 3
var s4 = make([]int, 3, 5)    //len = 3,cap = 5
var s5 = [][]int{
	{1}, {2, 3}, //二维数组的列是相等的,但二维切片的列可以不相等
}

切片获取 len 和 cap

var s1 = []int{1, 2, 3, 4, 5}
fmt.Printf("len = %d, cap = %d", len(s1), cap(s1))

切片追加元素

var s1 = []int{1, 2, 3, 4, 5}
s1 = append(s1, 100)
fmt.Println(s1)	// 1 2 3 4 5 100

切片的截取

// 定义一个 切片
var s1 = []int{1, 2, 3, 4, 5}
// 定义一个切片,切片的数据是用另一个切片截取而来
var s2 = s1[1:3]
fmt.Println(s2) // 2 3
操作 说明
s[n] 切片s中索引位置为n的值
s[:] 从切片s的索引位置0到len(s)-1所获得的切片
s[low:] 从切片s的索引位置low到len(s)-1所获得的切片
s[:high] 从切片s的索引位置0到high所获得的切片,len=high,cap不变
s[low:high] 从切片s的索引位置low到high所获得的切片,len=high-low,cap=cap-low
s[low:high:max] 从切片s的索引位置low到high所获得的切片,len=high-low,cap=max-low
len(s) 获取切片s的长度,总是<=cap(s)
cap(s) 获取切片s的容量,总是>=len(s)

注意:切片截取不是拷贝,是共用同一块内存,新的切片值被改变,原来的切片值跟着改变,当新的切片进行追加时,如果cap小于原来切片的cap,那么新的切片追加的值会覆盖原来切片相应下标的数据。如果cap超过原来切片的cap,那么新的切片会重新分配一块新的内存空间,不再和原来的切片共用同一块内存,对新切片的操作也不再影响原来的切片


字符串

string是常量,不能修改其中的字符。

string可以转换为[]byte或[]rune类型。

string底层是byte数组,string的长度就是该byte数组的长度,UTF-8编码中一个汉字占3个byte,即一个汉字占3个长度。

字符串的初始化

var s string = "你好,Go"
s1 := "你好,Go"
s2 := `你好,Go`	// ``号中的字符串原样输出,包括空格换行等
操作 说明
len(str) 获取字符串的长度
strings.Split 分割
strings.Contains 判断是否包含,是返回true
strings.HasPrefix 判断前缀是否匹配
strings.HasSuffix 判断后缀是否匹配
strings.Index 获取字符在字符串中首次出现的位置
strings.LastIndex 获取字符在字符串中最后出现的位置

字符串拼接

s1 := "a"
s2 := "b"
s3 := "c"
s4 := "d"
// 方式一
merged1 := s1 + s2 + s3 + s4
// 方式二
merged2 := fmt.Sprintf("%s%s%s%s", s1, s2, s3, s4)
// 方式三
merged3 := strings.Join([]string{s1, s2, s3, s4}, "") // 数组转成字符串
// 方式四
merged4 := strings.Builder{}
merged4.WriteString(s1);merged4.WriteString(s2);merged4.WriteString(s3);merged4.WriteString(s4)
fmt.Println(merged1, merged2, merged3, merged4.String())

数据类型转换

强制类型转换

低精度向高精度转换没问题,高精度向低精度转换会丢失精度。

无符号向有符号转换,最高位是符号位。

byte和int可以相互转换。bool和int不能相互转换。

float和int可以相互转换,小数位会丢失。

var a int = 1
b := string(a)    // 把 int 强制转换成 string 类型
fmt.Printf("%T", b)

数据类型转换

var i int = 8
var i64 int64 = int64(i)
// int 转 string
var s = strconv.Itoa(i)
s = strconv.FormatInt(i64, 10) // 10进制
fmt.Printf("%T", s)

// string 转 int
i, _ = strconv.Atoi(s)
fmt.Println(i)
i64, _ = strconv.ParseInt(s, 10, 64) // 10进制,32位/64位

// float 转 string
var f float64 = 1.123
s = strconv.FormatFloat(f, 'f', 2, 64) // f %f的意思,保留2位小数,64位
// string 转 float
f, _ = strconv.ParseFloat(s, 64)

// string []byte 相互转换
var b []byte = []byte(s)
s = string(b)

// string []rune 相互转换
var r []rune = []rune(s)
s = string(r)

map数据类型

map类型是一个K/V键值对存储的数据类型,key通过hash算法生成hash值,hash值的低位取模槽位(可以理解为容量,go的底层存储是hash表,表中有多个表节点,即槽位,一个槽位最多存放8对K/V组合,如果存储满了通过overflow指向下一个槽位),获取value存储的槽位的节点,通过高位查询节点中的数据。

map的初始化

var m1 map[string]int                  // 声明map, 指定key的数据类型是string,value的数据类型是int
m2 := make(map[string]int)             // 初始化,容量是0
m3 := make(map[string]int, 200)        // 初始化,容量是200,建议初始化时指定map的容量,减少map扩容
m4 := map[string]int{"语文": 2, "数学": 3} // 初始化时赋值

map的添加和删除

m := map[string]int{"语文": 2, "数学": 3} // 初始化时赋值

m["英语"] = 10    // 向map中添加数据

m["英语"] = 20    // 向map中添加数据,如果key之前有值,会覆盖之前的value数据

delete(m, "英语") // 从map中删除key对应的键值对数据

len(m)            // 获取map的长度

// map不支持使用cap函数

map的查询

value := m["语文"]
fmt.Println(value)

map的遍历

m := map[string]int{"语文": 2, "数学": 3}
for key, value := range m {
	fmt.Printf("key = %s, value = %d\n", key, value)
}

channel 管道数据类型

管道是一个环形先进先出的队列,send(插入)和recv(取走)从同一个位置沿同一个方向顺序执行。

sendx:表示最后一次插入元素的位置。

recvx:表示最后一次取走元素的位置。

管道的声明

// ch 定义的管道变量
// chan 管道类型关键字
// int 管道里面存放的数据类型
var ch chan int

管道的初始化

// 管道的环形队列里面可容纳8个int类型的长度
ch = make(chan int, 8)

管道的声明时初始化

var ch = make(chan int, 8)

向管道中插入数据        // 管道写满后再写入会阻塞报错,没有自动扩容的这种机制

// 向管道中插入元素,使用 <- 符号
// 语法: 变量 <- 要插入的数据
ch <- 10
ch <- 20
ch <- 50

从管道中取出数据        // 管道写满后,不可以再写入,有数据被取出后,可以再向管道中写

// 向管道中取出元素
// 语法: 赋值变量 = <-管道变量
var v = <-ch
fmt.Println(v)
v = <-ch
fmt.Println(v)
v = <-ch
fmt.Println(v)

遍历管道

// 遍历管道,遍历管道中剩余的元素
close(ch) // range方式遍历前必须先关闭管道,禁止再写入元素
for value := range ch {
	fmt.Println(value)
}

你可能感兴趣的:(Golang,golang)