介绍 |类型|值和引用|描述| |–|–| |整数类型|值类型|int、int8、int16、int32、int64、uint、uint8、uint16、uint32、uint64、byte,默认值是0| |浮点类型|值类型|float32、float64,默认值是0| |字符型|值类型|byte,没有专门的字符型,使用byte来保存单个字母字符| |布尔型|值类型|bool,默认值是false| |字符串|值类型|string,默认值是""
| |数组|值类型|| |结构体|值类型|struct| |指针|引用类型|*
| |管道|引用类型|channel| |函数|引用类型|也是一种类型| |切片|引用类型|slice| |接口|引用类型|interface| |映射|引用类型|map|
值类型: 变量直接存储值,内存通常在栈中分配引用类型: 变量存储的是一个地址,这个地址对应的空间才真正存储数据的值,内存通常在堆上分配,当没有任何变量引用这个地址时,该地址对应的数据空间就称为一个垃圾,由GC来回收
字符串 字符串就是一串固定长度的字符连接起来的字符序列。Go的字符串是由单个字符连接起来的。Go语言的字符串的字节使用UTF-8编码标识Unicode文本。
字符串要点
字符串一旦赋值了,字符串就不能修改,在Go中字符串是不可变的 双引号,会识别转义字符 反引号,以字符串的原生形式输出 字符串拼接使用 + 号 当一个拼接操作很长是,可以分行写
字符串表示形式
双引号,会识别转义字符 反引号,以字符串的原生形式输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 package main import "fmt" func main () { var str1 string = "hello" var str2 string = ` package main // 表示文件所在的包名,在go中,每个文件都必须属于一个包 import "fmt" // 引入fmt包 // 逐个逐个地定义全局变量 var g1 = 100 var g2 = "tom" // 一次性定义多个全局变量 var ( g3 = 11 g4 = "jim" ) // 定义主函数 func main() { // 1. 声明不赋值,使用默认值 var i int // 2. 根据值自信判断变量类型(类型推导) var num = 10.11 // 3. 省略var,使用:= name := "tom" // 4. 一次性声明多个 var n1, n2, n3 int // 5. 一次性赋值多个 // n4 = 100 // n5 = "tom" // n6 = 101 var n4, n5, n6 = 100, "tom", 101 } ` var str3 = "hello " + "world" var str4 = "hello " + "hello " + "world " + "world" + "hello world!" fmt.Println(str1) fmt.Println(str2) fmt.Println(str3) fmt.Println(str4) }
string和slice string底层是一个byte数组,因此string也可以进行切片处理
string可以通过切片的方式,先修改切片内容在转换回字符串,从而修改字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package main import ( "fmt" ) func main () { var str = "中国1234567890" var slic1 = str[0 :7 ] fmt.Println(slic1) var slic2 = []rune (str) slic2[0 ] = '汉' str = string (slic2) fmt.Println(str) }
指针 1 2 3 4 5 6 7 8 9 10 11 12 package main import ( "fmt" ) func main () { var num int = 1 var ptr *int = &num fmt.Printf("ptr %v %v" , &ptr, *ptr) }
数组 数组可以存放多个同一类型数据。数组也是一种数据类型,在Go中,数组是值类型
数组要点
数组是多个相同类型数据的组合,一个数组一旦声明/定义,其长度是固定的,不能动态变化 数组中的元素可以是任何数据类型,包括值类型和引用类型,但不能混用 数组创建后,如果没有赋值,元素的值都是数组类型的默认值 数组的下标从0开始 数组下标必须在指定范围内使用,否则报panic:数组越界 数组是值类型,在默认情况下是值传递,因此会进行值拷贝。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 package main import ( "fmt" ) func main () { var nums [5 ]int nums[0 ] = 0 nums[1 ] = 1 nums[2 ] = 2 nums[3 ] = 3 nums[4 ] = 4 fmt.Printf("nums 地址 = %p, nums [%d] 地址 = %p\n" , &nums, 1 , &nums[1 ]) var nums2 [5 ]int = [5 ]int {1 , 2 , 3 , 4 , 5 } fmt.Println(nums2) var nums3 = [5 ]int {1 , 2 , 3 , 4 , 5 } fmt.Println(nums3) var nums4 = [...]int {1 , 2 , 3 , 4 , 5 } fmt.Println(nums4) var nums5 = [5 ]int {2 :1 , 3 :2 , 4 :3 , 0 :4 , 1 :5 } fmt.Println(nums5) for i := 0 ; i < len (nums5); i++{ fmt.Println(nums5[i]) } for i, val := range nums5 { fmt.Println(i, val) } for _, val := range nums5 { fmt.Println(val) } }
二维数组 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 package main import ( "fmt" ) func main () { var arr [4 ][5 ]int ; arr[1 ][2 ] = 1 arr[1 ][3 ] = 1 arr[1 ][4 ] = 1 fmt.Println(arr) var arr2 = [2 ][3 ]int {{1 ,2 ,3 },{4 ,5 ,6 }} fmt.Println(arr2) var arr3 = [...][3 ]int {{1 ,2 ,3 },{4 ,5 ,6 }} fmt.Println(arr3) for i := 0 ; i < len (arr3); i++ { for j := 0 ; j < len (arr3[i]); j++ { fmt.Print(arr3[i][j]) } } fmt.Println("" ) for _, v := range arr3 { for _, v2 := range v { fmt.Print(v2) } } }
切片 可以理解是一个动态数组,从底层来说,其实就是一个struct结构体。
切片要点
切片是数组的一个引用,因此切片是引用类型,进行传递时,准守引用传递的机制 切片的使用和数组类似,遍历切片、访问切片的元素和求切片长度都一样 切片的长度是可以变换的,因此切片是一个可以动态变化数组 切片引用数组,切片内容改变, 数组内容也会改变 切片可以继续切片
切片创建方式
定义一个切片,然后让切片去引用一个创建好的数组var slice = arr[1:3] var slice = arr[0:end],可以简写arr[:end] var slice = arr[start:len(arr)],可以简写arr[start:] var slice = arr[0:len(arr)],可以简写arr[:] 通过make来创建 定义一个切片,直接指定具体数组
切片append操作原理
切片append操作的本质就是对数组扩容 go底层会创建一个新的数组newArr(安装扩容后大小) 将slice原来包含的元素拷贝到新的数组newArr slice重新引用到newArr newArr是底层来维护,程序员不可见
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 package main import ( "fmt" ) func main () { var nums [5 ]int = [5 ]int {1 , 2 , 3 , 4 , 5 } var slic = nums[1 :3 ] fmt.Println("切片内容:" , slic) fmt.Println("切片元素个数:" , len (slic)) fmt.Println("切片容量:" , cap (slic)) var slic2 []int = make ([]int , 5 , 10 ) slic2[1 ] = 10 slic2[3 ] = 10 fmt.Println(slic2) var slic3 []int = []int {1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 } fmt.Println(slic3) var slic4 []int = slic3[1 :3 ] fmt.Println(slic4) slic4 = append (slic4, 100 , 101 , 102 ) fmt.Println(slic4) slic4 = append (slic4, slic4...) fmt.Println(slic4) var slic5 = make ([]int , 20 ) copy (slic5, slic4) fmt.Println(slic5) }
map
1 var 变量名 map [keytype]valuetype
map注意点
map声明不分配内存,需要make来分配内存才可以使用。 Go中map是无序的,跟添加的顺序也无关,每次遍历得到的顺序是不固定的 map的容量达到后,再给map添加元素,会自动扩容,并不会发生panic,也说明map能动态的增长键值对
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 package main import ( "fmt" ) func main () { var m map [string ]string m = make (map [string ]string , 10 ) m["one" ] = "111" m["two" ] = "222" fmt.Println(m) var m2 = make (map [string ]string , 10 ) fmt.Println(m2) var m3 = map [string ]string { "one" :"111" , "two" :"222" , } fmt.Println(m3) delete (m3, "one" ) fmt.Println(m3) var val, findRes = m3["one" ] if findRes { fmt.Println("找到值 " , val) } else { fmt.Println("没有找到值 " ) } for k, v := range m3 { fmt.Printf("k=%v v=%v\n" , k, v) } }
map和slice 切片的数据类型如果是map,则我们成为slice of map,map切片,这样使用map的个数就可以动态变化了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package main import ( "fmt" ) func main () { var monsters []map [string ]string monsters = make ([]map [string ]string , 2 ) if monsters[0 ] == nil { monsters[0 ] = make (map [string ]string , 2 ) monsters[0 ]["name" ] = "monster1" monsters[0 ]["fight" ] = "444" } if monsters[1 ] == nil { monsters[1 ] = make (map [string ]string , 2 ) monsters[1 ]["name" ] = "monster2" monsters[1 ]["fight" ] = "1111" } var newMonster = map [string ]string { "name" :"monster3" , "fight" :"222" , } monsters = append (monsters, newMonster) fmt.Println(monsters) }
map排序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package main import ( "fmt" "sort" ) func main () { var map1 = make (map [int ]int , 10 ) map1[10 ] = 14 map1[1 ] = 53 map1[4 ] = 22 map1[7 ] = 70 fmt.Println(map1) var keys []int for k, _ := range map1 { keys = append (keys, k) } sort.Ints(keys) fmt.Println(keys) for _, k := range keys { fmt.Println(k, map1[k]) } }
类型转换 Go在不同类型的变量之间赋值时需要显示转换,也就是说Golang中数据类型不能自动转换
数值类型转换
Go中,数据类型的转换可以是从表示范围小->表示范围大,也可以是范围大->范围小 被转换的是变量存储的数据,变量本身的数据类型并没有变化 在转换中,当结果范围不一致时,按溢出处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 package main import ( "fmt" ) func main () { var i32 int32 = 100 var f32 float32 = float32 (i32) var i8 int8 = int8 (i32) fmt.Println("i32=%v f32=%v i8=%v" , i32, f32, i8) }
基础类型转string类型
使用 fmt.Sprintf() 进行转换 使用strconv 包的函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package main import ( "fmt" "strconv" ) func main () { var num1 int = 99 var num2 float32 = 11.22 var str1 string = fmt.Sprintf("%d %f" , num1, num2) var str2 string = strconv.FormatInt(int64 (num1), 10 ) fmt.Println(str1) fmt.Println(str2) }
string类型转基础数据类型
使用strconv 包的函数
string类型转基础数据类型注意事项
在将string类型转成基本数据类型是,要确保string类型能够转换成有效的数据。如果转换失败会转换成默认值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package main import ( "fmt" "strconv" ) func main () { var str string = "true" var b bool b, _ = strconv.ParseBool(str) fmt.Printf("b = %v" , b) }
类型断言 类型断言,由于接口是一般类型,不知道具体类型,如果要转成具体类型,就需要使用类型断言
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 package main import ( "fmt" ) func TypeJudge (items ...interface {}) { for i, x := range items { switch x.(type ) { case bool : fmt.Println("bool 类型" , i, x) case int : fmt.Println("int 类型" , i, x) case int8 : fmt.Println("int8 类型" , i, x) case int16 : fmt.Println("int16 类型" , i, x) case int32 : fmt.Println("int32 类型" , i, x) case int64 : fmt.Println("int64 类型" , i, x) } } } func main () { var x interface {} var y int32 = 1 x = y var z, res = x.(int64 ) if res == true { fmt.Println("类型转换成功" , z) } else { fmt.Println("类型转换失败" ) } TypeJudge(1 , false , 2 , 3 ) }