# go_basic_code **Repository Path**: goku_black/go_basic_code ## Basic Information - **Project Name**: go_basic_code - **Description**: go_basic_code - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-04-28 - **Last Updated**: 2021-04-28 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Golang环境 ## 1.Golang环境搭建 ### 1.1 linux ### 1.2 macos ### 1.3 windows ## 2.Golang项目的目录结构 ``` --pkg --bin --src --crm --app.go ``` ## 3.Golang项目运行方式 ### 3.1 第一种运行方式 ```shell // 直接运行 go run main.go ``` ### 3.2 第二种运行方式 ```shell // 编译为可执行文件 go build // 执行可执行文件 app.exe ``` ### 3.2 第三种运行方式 ```shell // 生产可执行文件默认放在bin目录 go install ``` # Golang基础 ## 1.Golang包管理 关于包的总结: - 一个文件夹可以成为一个包 - 早文件夹(包)中可以创建多个文件 - 在用一个包文件夹(包)下的每一个文件中必须指定包名称,且包名称要相同 关于包的分类: - main包 - main包里必须有main函数 - main函数就是项目的入口 - 非main包' - 用来拆分代码 ## 2.Golang输出发fmt.Println 控制台输出推荐使用fmt.Println(),因为go本身的输出语句后面可能不更新了 ```go package main import ( "fmt" ) func main(){ fmt.Println("今天真开心") //控制台输出 fmt.Printf("今天真%s","开心呢")//格式化字符串 } ``` ## 3.Golang注释 ### 3.1 单行注释 ```go //表示单行注释 ``` ### 3.2 多行注释 ```go /* 多行注释 */ ``` ## 4.Golang数据类型 - 整型-整数 - 字符串-文本 - 布尔型-真假 ```go package main import "fmt" func main(){ //整型 fmt.Println(666) fmt.Println(1+1) fmt.Println(2/2) fmt.Println(2*2) fmt.Println(1-1) fmt.Println(3%2) //字符串 双引号包裹起来 fmt.Println("字符串类型") fmt.Println("钓鱼要钓刀鱼,刀鱼要到岛上钓") fmt.Println("zyt"+"dpl")//输出没有空格 //布尔 fmt.Println(1>2) //false fmt.Println(1<2) //true fmt.Println("ALEX"== "SB") //true if 2>1 { fmt.Println("那你可真牛啊") } else { fmt.Println("你个小垃圾") } } ``` ## 5.Golang变量 ### 5.1 变量声明的意义 - 变量可以存储数据 - 变量可以重复使用 ```go package main import "fmt" func main(){ var name string = "tom" fmt.Println("name:",name) var age int = 18 fmt.Println("age:", age) var flag bool = true fmt.Println("bool:", flag) } ``` ### 5.2 变量名要求 - 变量名只能包括字母、数字、下划线 - 数字不能开头 - 不能使用go内置关键字 - break、default、select、interface、case、map、const、if、range、type ![image-20210411023626816](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210411023626816.png) ```go //变量名只能由字母数字下划线 var add? string = "1" 错误 // 数字不能开头 var 1add int = 1 错误的 // 不使用go关键字 var var string = "1" ``` - 建议 - 变量名见名知意 - 驼峰命名 - myBossName ### 5.3 变量名简写 - 声明+赋值 ```go var name string = "abc" var name = "abc" var := "abc" ``` - 先声明再赋值 - string默认值空串 - int默认值0 - bool默认值false ```go var name string var age string var phone string var name,age,phone string name = "abc" age = "18" phone = "123123123" ··· var ( name = "abc" age = "18" phone = "123123123" ) ``` ### 5.4 变量的作用域 - 变量的子作用域大于父级作用域 ### 5.5 作用域和内存 示例1: ```go //引用 name := "武沛齐" ``` ![image-20210411045006681](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210411045006681.png) 示例2: ```go // golang会copy一份给新的nickname name := "武沛齐" nickname := name ``` ![image-20210411044956019](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210411044956019.png) 示例3: ```go // 变量重新赋值后会覆盖原来的值 name := "武沛齐" nickname := name name = "alex" ``` ![image-20210411045125499](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210411045125499.png) ##### 注意事项:使用int、string、bool这三种数据类型,如果变量赋值会拷贝一份【值类型】 ## 6.Golang常量 - 常量是不能修改的变量 - 关键字是const - 一般情况常量定义在全局 【因为常量不能被修改】 ```go package main import "fmt" //全局常量 const ( v3 = 1123 v4 = 4156 //v3 = int 错误的 不能修改 ) func main(){ //定义常量 //const age int = 89 const age = 98 //简写 fmt.Println(age) const ( v1 = 123 v2 = 456 //v3 = int 错误的 不能修改 ) } ``` - iota - 可有可无 常量的计数器 ```go package main import "fmt" // 全局iota const ( mon = iota + 1 tue wed thu fir sat sun ) func main() { //示例1 //const ( // v1 = iota // v2 = iota // v3 = iota // v4 = iota // v5 = iota //) //示例2 //fmt.Println(v1,v2,v3,v4,v5) //const ( // v1 = iota // v2 // v3 // v4 // v5 // ) //fmt.Println(v1,v2,v3,v4,v5) //示例3 从非0开始计数 //const ( // v1 = iota + 2 // v2 // v3 // v4 // v5 //) //fmt.Println(v1,v2,v3,v4,v5) //示例3 从非0开始计数 const ( v1 = iota _ //占用一个位置 v2 v3 v4 v5 ) fmt.Println(v1,v2,v3,v4,v5) } ``` ## 7.Golang输入 让用户输入,完成信息的校验 。 - fmt.scan - fmt.scan要求输入两个值 必须输入两个 输入一个会一直等待 ```go package main import "fmt" func main(){ //示例1: //var name string //声明变量 //fmt.Println("请输入用户名") //fmt.Scan(&name)//将输入的内容的内存放在name对应的内存地址 //fmt.Println(name) //示例2: var name string //声明变量 var age int fmt.Println("请输入用户名") //count 声明了不用会报错 用_下划线代替 //count,err := fmt.Scan(&name,&age)//将输入的内容的内存放在name对应的内存地址 _,err := fmt.Scan(&name,&age)//将输入的内容的内存放在name对应的内存地址 if err == nil { fmt.Println(name,age) }else { fmt.Println("用户输入的信息错误",err) } //fmt.scan要求输入两个值 必须输入两个 输入一个会一直等待 } ``` - fmt.scanln - fmt.scan要求输入两个值 如果输入一个 再回车会直接跳过 ```go package main import "fmt" //scan func main(){ //示例1: //var name string //声明变量 //fmt.Print("请输入用户名") //fmt.Scanln(&name)//将输入的内容的内存放在name对应的内存地址 //fmt.Println(name) //示例2: var name string //声明变量 var age int fmt.Println("请输入用户名") //count 声明了不用会报错 用_下划线代替 //count,err := fmt.Scan(&name,&age)//将输入的内容的内存放在name对应的内存地址 _,err := fmt.Scanln(&name,&age)//将输入的内容的内存放在name对应的内存地址 if err == nil { fmt.Println(name,age) }else { fmt.Println("用户输入的信息错误",err) } //fmt.scan要求输入两个值 如果输入一个 再回车会直接跳过 } ``` - fmt.scanf - 格式化字符串 ```go package main import "fmt" func main() { var name string fmt.Print("请输入用户名") count,err := fmt.Scanf("我叫%s 今年18岁",&name)// 自动提取name 后面还有文本要加空格 fmt.Println(name) fmt.Println(count,err) } ``` - 无法解决的问题 - 如果输入有空格 只会获取空格之前的 - 解决方法 - 标准输入 ```go package main import ( "bufio" "fmt" "os" ) func main(){ //问题 长文本有空格只能获取空格之前的 //var message string //fmt.Println("请输入个人信息:") //fmt.Scanln(&message) //fmt.Println(message) //解决方法 标准输入 reader:= bufio.NewReader(os.Stdin) // line 从stdin中读取一行的数据 (字节集合 转化为字符串) // reader默认一次读取4096个字节 // isPrefix 表示是否读取完了 // err 表示错误 //line,isPrefix,err := reader.ReadLine() line,_,_ := reader.ReadLine() data := string(line) fmt.Println(data) } ``` ## 8.Golang条件语句 ### 8.1 基本条件语句 ```go if true { ... } else{ ... } ``` ### 8.2 多条件 ```go if 条件1 { ... } else if 条件2{ ... } else if 条件3{ ... } else{ ... } ``` ### 8.3 嵌套条件语句 ![image-20210411141140942](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210411141140942.png) ## 9.Golang switch case语句 - 注意事项: - 数据的比较只能相同数据类型的比较 ```go switch num{ case 条件1: fmt.Println("等于1") case 条件2: fmt.Println("等于2") case 条件3: fmt.Println("等于3") case 条件4: fmt.Println("等于4") default: fmt.Println=("都不满足") } ``` ```go package main import ( "fmt" ) func main(){ var num int fmt.Println("请输入一个数字") fmt.Scan(&num)//将输入的内容的内存放在name对应的内存地址 switch num{ case 1: fmt.Println("等于1") case 2: fmt.Println("等于2") case 3: fmt.Println("等于3") case 4: fmt.Println("等于4") default: fmt.Println("都不满足") } } ``` ## 10.Golang的for循环 ### 10.1 for循环各种情况 ```go for 循环条件 { 循环体 } ``` ```go package main import ( "fmt" "time" ) func main(){ //示例1:死循环 //fmt.Println("循环开始") //for{ // fmt.Println("红鲤鱼绿鲤鱼与驴") // time.Sleep(time.Second+1)//等1秒执行一次 //} //fmt.Println("循环开结束") //示例2:for 加条件语句 //fmt.Println("循环开始") //for 2>1{ // fmt.Println("红鲤鱼绿鲤鱼与驴") // time.Sleep(time.Second+1)//等1秒执行一次 //} //fmt.Println("循环开结束") //示例3:for 加条件语句+结束 //fmt.Println("循环开始") //var num=1 //for num<5{ // fmt.Println("红鲤鱼绿鲤鱼与驴") // time.Sleep(time.Second+1)//等1秒执行一次 // num+=1 //} //fmt.Println("循环开结束") //示例4:for 布尔类型示例 fmt.Println("循环开始") var flag=true for flag{ fmt.Println("红鲤鱼绿鲤鱼与驴")1 time.Sleep(time.Second+1)//等1秒执行一次 flag=false } fmt.Println("循环开结束") } ``` ### 10.2 for循环中有变量和条件11 ```go ////示例5:for 循环体内声明变量 for i:=1;i<10;i+=1{ fmt.Println("zyt是我儿子") } ``` ## 11.Golang continue和break关键字 ### 11.1 continue 在for循环中,当遇到continue后会终止当前的循环 ### 11.2 break 在for循环中,当遇到break后会终止所有循环 ### 11.3 对for循环打标签 对for循环进行打标签,然后通过break和continue可以实现多层循环的终止和跳出 ```go f1: for i:=1;i<3;i++{ for j:=1;j<5;j++{ if j == 3 { continue f1 //跳出f1的当前循环 } fmt.Println(i,j) } } ``` ```go f2: for i:=1;i<3;i++{ for j:=1;j<5;j++{ if j == 3 { break f2 //跳出f2的当前循环 } fmt.Println(i,j) } } ``` ## 12. Golang goto关键字 goto关键字可以跳转到指定的行 ![image-20210411163332832](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210411163332832.png) ## 13. 字符串格式化 将数据格式化为特定格式的字符串。 ```go package main import "fmt" func main(){ var name,address,action string fmt.Println("请输入姓名:") fmt.Scanln(&name) fmt.Println("请输入位置:") fmt.Scanln(&address) fmt.Println("请输入行为:") fmt.Scanln(&action) result := fmt.Sprintf("我叫%s,在%s上%s",name,address,action) fmt.Println(result) } ``` ## 14.运算符 ### 14.1 关系运算符 ``` + - * / % ++ 自增 -- 自己 ``` ### 14.2 关系运算符 ``` >= <= > < == != ``` ### 14.3 逻辑运算符 ``` && and || or ! not ``` ### 14.4 位运算符 ``` & | ^ << >> ``` 必知必会概念 - 计算机中的存储、运算、网络传输的行为都是二进制的 - 二进制的表示形式 - 二进制 - 十进制 - 十进制和二进制 的转换 ![image-20210411190122993](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210411190122993.png) ### 14.5 赋值运算符 ``` = += -= *= /= %= <<= >>= &= ^= |= ``` ![image-20210411190321814](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210411190321814.png) ### 14.6 运算符的优先级 ``` precedence Operator 5 * / % << 》》 & &^ 4 + - | ^ 3 == != < <= > >= 2 && 1 || ``` # Golang进制、单位、编码 ## 1.进制 - 计算机的本质底层都是二进制 - 八进制、十进制、十六进制之间的对应关系 - 满N进1 ![image-20210411191217188](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210411191217188.png) ## 2.单位 - 计算机的底层都是二进制的 ``` 1100101010101010101 ``` 由于计算机中本质上所有的东西以为二进制存储和操作的,为了方便对于二进制值大小的表示,所以就搞了一些单位,例如:流量还有多少M、硬盘容量有1T、计算机8G内存等、宽带是200M、千兆网络等。 计算机中表示对于二进制大小的常见单位有: - b(bit),位 ``` 表示二进制有多少位,例如: 01101 就是 5位 = 5b 011011010 就是 9位 = 9b ``` - B(byte),字节 ``` 8位就是1个字节,例如: 10100101 就是 8位 = 8b = 1B= 1个字节 1010010110100101 就是 16位 = 16b = 2B= 2个字节 ``` - KB(Kilobyte),千字节 ``` 1024个字节就是1千字节(1KB),即: 1 KB = 1024 B = 1024*8 b ``` - M(Megabyte),兆 ``` 1024个千字节就是1兆(1M),即: 1M = 1024 KB = 1024 * 1024 B = 1024 * 1024 * 8 b ``` - G(Gigabyte),千兆 ``` 1024个兆就是1千兆(1G),即: 1G = 1024 M = 1024 * 1024 KB = 1024 * 1024 * 1024 B = 1024 * 1024 * 1024 * 8 b ``` - T(Terabyte),万亿字节 ``` 1024个G就是1T ``` - …其他更大单位 PB/EB/ZB/YB/BB/NB/DB 不再赘述。 学完上面的这些单位之后,是不是就了解了平时大家说的自己有1G流量是啥意思了。 ## 3.编码 ### 3.1 ascii编码 最多用二进制的八位来表示所有的情况。 ```go 00000000 00000001 00000010 ........ 11111111 2**8=256个 ``` ascii编码有256个 ### 3.2 unicode(万国码) - us2,用16为来表示所有的情况。2**16=65536 0-65545 ``` 00000000 00000000 ... ... 11111111 11111111 ``` - us4,用32为来表示所有的情况。 ``` 00000000 00000000 00000000 00000000 ... ... 11111111 11111111 11111111 11111111 ``` 注意:us2和us4根据情况来选 ### 3.3 utf-8编码 - **第二步**:码位以二进制展示,再根据模板进行转换找模板 ``` 码位范围(十六进制) 转换模板 0000 ~ 007F 0XXXXXXX 0080 ~ 07FF 110XXXXX 10XXXXXX 0800 ~ FFFF 1110XXXX 10XXXXXX 10XXXXXX 10000 ~ 10FFFF 11110XXX 10XXXXXX 10XXXXXX 10XXXXXX 例如: "B" 对应的unicode码位为 0042,那么他应该选择的一个模板。 "ǣ" 对应的unicode码位为 01E3,则应该选择第二个模板。 "武" 对应的unicode码位为 6B66,则应该选择第三个模板。 "沛" 对应的unicode码位为 6C9B,则应该选择第三个模板。 "齐" 对应的unicode码位为 9F50,则应该选择第三个模板。 注意:一般中文都使用第三个模板(3个字节),这也就是平时大家说中文在utf-8中会占3个字节的原因了 ``` - **第二步**:码位以二进制展示,再根据模板进行转换 ``` 码位拆分: "武"的码位为6B66,则二进制为 0110101101100110 根据模板转换: 6 B 6 6 0110 1011 0110 0110 ---------------------------- 1110XXXX 10XXXXXX 10XXXXXX 使用第三个模板 11100110 10XXXXXX 10XXXXXX 第一步:取二进制前四位0110填充到模板的第一个字节的xxxx位置 11100110 10101101 10XXXXXX 第二步:挨着向后取6位101101填充到模板的第二个字节的xxxxxx位置 11100110 10101101 10100110 第二步:再挨着向后取6位100110填充到模板的第三个字节的xxxxxx位置 最终,"武"对应的utf-8编码为 11100110 10101101 10100110 ``` 总结: 本章的知识点属于理解为主,了解这些基础之后有利于后面知识点的学习,接下来对本节所有的知识点进行归纳总结: 1. 计算机上所有的东西最终都会转换成为二进制再去运行。 2. ascii编码、unicode字符集、utf-8编码本质上都是字符与二进制的关系。 - ascii,字符和二进制的对照表。 - unicode,字符和二进制(码位)的对照表。 - utf-8,对unicode字符集的码位进行压缩处理,间接也维护了字符和二进制的对照表。 3. ucs2和ucs4指的是使用多少个字节来表示unicode字符集的码位。 4. 目前最广泛的编码为:utf-8,他可以表示所有的字符且存储或网络传输也不会浪费资源(对码位进行压缩了)。 5. 二进制、八进制、十进制、十六进制其实就是进位的时机不同。 6. 一个字节8位 7. b/B/KB/M/G的关系。 ![image-20210411223105386](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210411223105386.png) # Golang数据类型 数据类型,其实就是各种各样的数据。 Go语言中常见的数据类型有很多例如 - 整形 - 浮点型 - 布尔型 - 字符串 - 数组 - 指针 - 切片 - 字典 - 结构体 - 接口 ## 1.整形 | 序号 | 类型和描述 | | ---- | ------------------------------------------------------------ | | 1 | **uint8** 无符号 8 位整型 (0 到 255) | | 2 | **uint16** 无符号 16 位整型 (0 到 65535) | | 3 | **uint32** 无符号 32 位整型 (0 到 4294967295) | | 4 | **uint64** 无符号 64 位整型 (0 到 18446744073709551615) | | 5 | **int8** 有符号 8 位整型 (-128 到 127) | | 6 | **int16** 有符号 16 位整型 (-32768 到 32767) | | 7 | **int32** 有符号 32 位整型 (-2147483648 到 2147483647) | | 8 | **int64** 有符号 64 位整型 (-9223372036854775808 到 9223372036854775807) | - int - 在32为操作系统中(-2147483648 到 2147483647) 2**32 - 在64为操作系统中( -9223372036854775808 到 9223372036854775807) 2*64 ### 1.1 整形的相互转换 要转换成声明就用什么函数包裹起来 ``` package main import "fmt" func main(){ var v1 int8 = 1 var v2 int16 = 2 var v3 = int16(v1)+v2) //将v1转换为int16 fmt.Println(v3) } ``` 注意: - 低位转高位不会出问题 - 高位转为低位置可能会有问题 ### 1.2 整形和字符串的转换 - 整形 转换 字符串 - strconv.Itoa() 整数转为字符串 - 转换的之后只能是int类型 不能是int8,int16,int32 ```go // 整形和字符串的转换 // strconv.Itoa() 整数转为字符串 v6 := 19 result := strconv.Itoa(v6) fmt.Println(result,reflect.TypeOf(result)) // 转换的之后只能是int类型 不能是int8,int16,int32 var v7 int8 = 123 result2 := strconv.Itoa(int(v7)) fmt.Println(result2,reflect.TypeOf(result2)) ``` - 字符串 转为 整形 - 转换失败后result3还是int的初始值 ``` // strconv.Atoi() 字符串转为数字 v8 := "000i" result,err := strconv.Atoi(v8) fmt.Println(result,reflect.TypeOf(result)) fmt.Println(err,reflect.TypeOf(err)) ``` ### 1.3 进制转换 - Go代码中: - 十进制中,整形的方式存在 - 其他进制,字符串方式存在 - 整形,10进制 ```go // 字符串转换 //data:要转换的文本 //2: 将字符串按照2进制处理转换为10进制 //16: 转换过程中的约束不能超过int16的范围 //result: 永远是int64() data := "1010101001" result,err := strconv.ParseInt(data,2,16) fmt.Println(result,err) ``` - 通过Parseint转换的时候 ,本质上和Atoi是相同的 ![image-20210412003521025](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210412003521025.png) ### 1.4 数学运算 ![image-20210412004239477](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210412004239477.png) ### 1.5 指针/nil/变量声明/new - 声明变量 ``` var v1 int v2 := 999 ``` ![image-20210412004454680](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210412004454680.png) - 指针 - 创建一个内存,内存中存储了真正的数据存放的地址 - 指针是为了节省内存 ```go var v3 *int //声明一个int类型的指针 v4 := new(int) //声明一个int类型的指针 ``` ![image-20210412004954504](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210412004954504.png) - new ``` new用于创建内存并进行内部数据的初始化,并返回一个指针 ``` - nil ``` nil是空值 ``` - 指针默认为nil ### 1.6 超大整型 ```go //超大整形 //创建一个超大整形 var v1 big.Int //var v2 *big.Int //一般用不到(直接赋值的时候用) v3:=new(big.Int) //第二步 在超大整形中写入值 v1.SetInt64(1990) v1.SetString("92358203984",10) //将字符串已10进制写在v1中 v3.SetInt64(1990) v3.SetString("92358203984",10) //将字符串已10进制写在v1中 ``` 第一步:创建超大整形对象 ```go //第一步:床i教案一个超大整形的对象 var v1 big.Int var v2 big.Int //第二步:在超大整形对象中写入值 v1.SetInt64(93492342394234) fmt.Println(v1) v2.SetString("237498237489023042809428093408240394",10) fmt.Println(V2) ``` ```go //第一步:床i教案一个超大整形的对象 v3 := new(big.Int) v4 := new(big.Int) //第二步:在超大整形对象中写入值 v3.SetInt64(2348920384923840923490) fmt.SetString(v3) v4.SetInt64("237498237489023042809428093408240394",10) fmt.Println(v4) ``` 推荐:使用指针的方式:即使用new来创建和初始化对象 第二步:基本的加减乘除 - 加法 ```加法 //v1 := new(big.Int) //v1.SetInt64(89) //v2 := new(big.Int) //v2.SetInt64(89) v1 := big.NewInt(69) v2 := big.NewInt(89) res := new(big.Int) res.Add(v1,v2) fmt.Println(res) ``` - 其他 ```go v1 := big.NewInt(69) v2 := big.NewInt(68) res := new(big.Int) //加 res.Add(v1,v2) fmt.Println(result) //减 res.Sub(v1,v2) fmt.Println(result) //乘 res.Mul(v1,v2) fmt.Println(result) //除 得到商 res.Div(v1,v2) fmt.Println(result) //除 得商和余数 minder := new(big.Int) result.DivMod(v1,v2,minder) fmt.Println(result,minder) ``` - 结果 ```go v1 := new(big.Int) v1.SetString("692354345324523453245345",10) v2 := new(big.Int) v2.SetString("68234523452352353525234523452345",10) result := new(big.Int) result.Add(v1,v2) fmt.Println(result.String()) ``` #### 建议: - 尽量new创建一个指针 - int和*int是两种类型 ## 2.浮点型 浮点数,算计中表示小数的类型,如3.14 Go语言中有两种浮点型: - float32,用32位(4个字节)来存储浮点数 - float64,用64位(8个字节)来存储浮点数 ```go package main import "fmt" func main() { var v1 float32 v1 = 3.14 v2 := 3.15 // 默认是float64 v3 := float64(v1) + v2 fmt.Println(v3) } ``` ``` >>>6.290000104904175 ``` ### 2.1 非精确的结果 浮点数处理的时候是非精确的计算 浮点数的底层存储原理导致的 ### 2.2 浮点数的存储原理 ```go var price flaot64 = 39.29 ``` **第一步:浮点数转型为二进制** - 整数部分,直接转换为二进制 - 小数部分,让小数部分乘2,结果小于1则乘2,结果小于1则将结果减1乘2,一直循环,直到结果等于一。 - 浮点数的小数部分就是将运算结果的整数部分拼接起来 ![image-20210412234101481](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210412234101481.png) **第二步:科学计数法表示** ![image-20210412234205992](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210412234205992.png) **第三步:存储** 以float32来进行存储,用32为来存储浮点型 ![image-20210412234308939](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210412234308939.png) - sign 用1位来表示浮点数的正负 - 1 正数 - 0 负数 - exponent 用8位来表示256中可能(0~255),含正负值(-127~128)。例如:5要存储到exponent位的话,需要让5+127=132,再将132转为二进制,存储在exponent。(132的二进制是01000010) - fraction存储小数点后的所有数据。超过23为不要了 float64和32类似只是`sign=1位` `exponent=11位` `fraction=52位`也就意味范围更大的 ### 2.3 decimal精确小数 Go语言内部没有decimal 第三方包,则需要在Go语言的环境中安装再使用 http://github.com//shopspring/decimal 使用步骤 **第一步:安装第三包** ``` go get github.com//shopspring/decimal ``` - 会放在`SRC`目录下,编译之后会放在`pkg`目录 **第二步:使用decimal包** ![image-20210412235426338](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210412235426338.png) ## 3.布尔型 表示真假。一般配合条件使用,用于满足一些操作 ```go package main import ( "fmt" "strconv" ) func main() { //字符串转换布尔、 //true:"1", "t", "T", "true", "TRUE", "True" //false: "0", "f", "F", "false", "FALSE", "False" result,err := strconv.ParseBool("true") fmt.Println(result,err) } ``` ## 4.字符串 ### 4.1 字符串的本质 计算机中的所有数据本质都是二进制 Go语言中的字符串是utf-8编码的序列。 ```go package main import ( "fmt" "strconv" "unicode/utf8" ) func main() { // 1.字符串的本质是utf-8序列 var name string = "武沛齐" // 武 11100110 10101101 10100110 fmt.Println(name[0],strconv.FormatInt(int64(name[0]),2)) fmt.Println(name[1],strconv.FormatInt(int64(name[1]),2)) fmt.Println(name[2],strconv.FormatInt(int64(name[2]),2)) // 沛 11100110 10110010 10011011 fmt.Println(name[3],strconv.FormatInt(int64(name[3]),2)) fmt.Println(name[4],strconv.FormatInt(int64(name[4]),2)) fmt.Println(name[5],strconv.FormatInt(int64(name[5]),2)) // 齐 11101001 10111101 10010000 fmt.Println(name[6],strconv.FormatInt(int64(name[6]),2)) fmt.Println(name[7],strconv.FormatInt(int64(name[7]),2)) fmt.Println(name[8],strconv.FormatInt(int64(name[8]),2)) // 2.获取字符串的长度 fmt.Println(len(name)) // 3.字符串转为字节的集合 byteSet := []byte(name) fmt.Println(byteSet) //[230 173 166 230 178 155 233 189 144] // 4.字节的集合转换位字符串 byteList := []byte{230, 173, 166, 230, 178, 155, 233, 189, 144} targetString := string(byteList) fmt.Println(targetString) //武沛齐 // 5.将字符串转unicode字符码点的集合-rune ucs4 tempSet := []rune(name) fmt.Println(tempSet) //[27494 27803 40784] fmt.Println(tempSet[0],strconv.FormatInt(int64(tempSet[0]),16)) //27494 6b66 unicode编码 fmt.Println(tempSet[1],strconv.FormatInt(int64(tempSet[1]),16)) //27803 6c9b unicode编码 fmt.Println(tempSet[2],strconv.FormatInt(int64(tempSet[2]),16)) //40784 9f50 unicode编码 // 6.rune集合转换位字符串 runeList := []rune{27494, 27803, 40784} targetName := string(runeList) fmt.Println(targetName) //武沛齐 // 7.长度的处理-字符串的长度 length := utf8.RuneCountInString(name) fmt.Println(length) // 3 } ``` ### 4.2 字符串的常见功能 #### 4.2.1 获取字符串的长度 ![image-20210413005145142](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210413005145142.png) #### 4.2.2 是否以xxx开头 ![image-20210413005152036](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210413005152036.png) #### 4.2.3 是否以xxx结尾 ![image-20210413005229259](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210413005229259.png) #### 4.2.4 是否包含 ![image-20210413005214847](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210413005214847.png) #### 4.2.5 转大写 ![image-20210413005323633](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210413005323633.png) #### 4.2.6 转小写 ![image-20210413005256506](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210413005256506.png) #### 4.2.7 去除两边 ![image-20210413005356477](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210413005356477.png) #### 4.2.8 替换 ![image-20210413005458539](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210413005458539.png) #### 4.2.9 分割 ![image-20210413005526564](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210413005526564.png) #### 4.2.10 拼接 ![image-20210413004415242](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210413004415242.png) #### 4.2.11 string转为int ![image-20210413004531784](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210413004531784.png) #### 4.2.12 int转为string ![image-20210413004556553](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210413004556553.png) #### 4.2.13 字符串和字符结合 ![image-20210413004629215](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210413004629215.png) #### 4.2.14 字符串和rune集合 ![image-20210413004701836](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210413004701836.png) #### 4.2.15 string和字符 ![image-20210413005046553](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210413005046553.png) - 应用场景:生成一个随机数,带入得到随机字符。 ### 4.3 字符串的索引、切片、循环 ![image-20210413010110528](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210413010110528.png) ## 5.数组 数组是定长且元素类型一致的集合。 ```go // 方式一:先声明再赋值 (内存中已开辟了空间 内存初始化的值为0) var numbers [3]int numbers[0] = 333 numbers[1] = 666 numbers[2] = 999 fmt.Println(numbers) // [333 666 999] // 方式二:先声明 后赋值 var names = [2]string{"胡皓","ALEX"} fmt.Println(names) // [胡皓 ALEX] // 方式三: 声明+赋值+指定位置 var ages = [3]int{0:87,1:73,2:34} fmt.Println(ages) //[87 73 34] // 方式四:省略个数 var ids = [...]string{"1","2","3"} //[1 2 3] fmt.Println(ids) var genders = [...]string{0:"nan",2:"other"}//[nan other] fmt.Println(genders) //var genders = [...]string{0:"nan",1:"nv",2:"other"}//[nan other] //fmt.Println(genders)// [nan nv other] ``` ```go // 指针数组 // 声明 指针类型的数组(指针类型) 不会开辟内存初始化数组中的值 numbers = nil var numbers *[3]int fmt.Println(numbers)// // 声明数组并初始化 返回的是指针类型的数组 genders := new([3]int) fmt.Println(genders)// &[0 0 0] ``` ### 5.1 数组的内存管理 ![image-20210414000601363](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210414000601363.png) 数组是定长且元素类型一致的集合。 必备知识点: - 数组的内存是连续的 - 数组的内存地址是数组的第一个元素的内存地址 - 创建字符串的时候,字符串内部存了:`len`+`str` 示例1: ![image-20210414000656422](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210414000656422.png) 示例2: ![image-20210414001125983](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210414001125983.png) 示例3: ![image-20210414001213054](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210414001213054.png) ### 5.2 数组的可变和拷贝 可变:数组的元素可以被更改(长度和类型不能修改) ```go names := [3]string{"alex","huhao","lufei"} names[0] = "yuanhao" ``` 字符串不可以被修改 拷贝:变量赋值的时候重新拷贝 ```go names1 := [3]string{"alex","huhao","lufei"} names2 = names1 names[1] = "afei" fmt.Println(names1,names2) ``` ### 5.3 索引、切片、循环、长度 - 长度 ```go names1 := [3]string{"alex","huhao","lufei"} fmt.Println(len(names1)) // 3 ``` - 索引 ```go //数组索引 names2 := [3]string{"alex","huhao","lufei"} fmt.Println(names2[0]) //alex fmt.Println(names2[1]) //huhao fmt.Println(names2[2]) //lufei ``` - 切片 ```go //数组切片 --包头不包尾 names3 := [3]string{"alex","huhao","lufei"} data := names3[0:1] //包头不包尾 fmt.Println(data) // [alex] ``` - 循环 ```go //循环 names4 := [3]string{"alex", "huhao", "lufei"} for i := 0; i < len(names4); i++ { fmt.Println(names4[i]) //alex huhao lufei } for key, item := range names4 { fmt.Println(key, item) //0 alex 1 huhao 2 lufei } for key, _ := range names4 { fmt.Println(key) //0 1 2 } for _, item := range names4 { fmt.Println(item) //ale huhao lufei } ``` ### 5.4 数组嵌套 ```go //嵌套数组 //声明后赋值 var data [2][3]int data[0] = [3]int{11,22,33} data[1] = [3]int{44,55,66} fmt.Println(data) //[[11 22 33] [44 55 66]] data[0][0] = 12 fmt.Println(data) //[[12 22 33] [44 55 66]] //声明+赋值 data2 := [2][3]int{[3]int{11,22,33},[3]int{44,55,66}} //[[11 22 33] [44 55 66]] fmt.Println(data2) ``` ## 6.切片 切片:动态数组 切片是Golang中重要的数据类型,每个切片对象内部都维护着:数组指针、切片长度、切片容量三个数据 ```go type slice struct{ } ``` ![image-20210414003829900](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210414003829900.png) 在向切片中追加数据个数大于容量的时候,容量会变为原来的两倍(当容量超过1024时候每次增加1/4) ![image-20210414004016528](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210414004016528.png) ### 6.1 创建切片 - 切片的数据类型 ```go //创建切片 var nums []int //创建切片 推荐 var data = []int{11,22,33} data := []int{11,22,33} //创建切片 推荐 //make只能用于切片、字典、channel var users = make([]int,2,5) ``` - 切片的指针类型 ```go //创建一个切片类型的指针 var v1 = new([]int) //创建一个切片类型的指针 指向 nil var v2 *[]int ``` ### 6.2 自动扩容 #### 6.2.1 没有扩容 如果没有扩容,原来的切片会多一个引用**容量、地址**相同,**长度**不同 ```go v1 := make([]int,1,3) fmt.Println(len(v1),cap(v1)) //获取长度和容量 // 其他 v2 := make([]int,3) ``` ![image-20210414004845921](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210414004845921.png) - append函数扩容切片 ```go v1 := make([]int,1,3) v2: = append(v1,66) fmt.Println(v1) // [0 ] fmt.Println(v2) // [0 66] v1[0] = 99 fmt.Println(v1) // [99 ] fmt.Println(v2) // [99 66] ``` ![image-20210414005202524](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210414005202524.png) ```go //需求:有一个切片,往切片中追加一个数据 v1 := make([]int,1,3) v1: = append(v1,66) ``` #### 6.2 扩容了 如果扩容了会创建一个新的切片**容量、长度、地址**都先同 ```go v1 := []int{11,22,33} v2 := append(v1,44) ``` ![image-20210414005649014](C:\Users\NINGMEI\AppData\Roaming\Typora\typora-user-images\image-20210414005649014.png) ### 6.3 常见操作 #### 6.3.1 长度和容量相关 - 长度:`len()` - 容量:`cap()` ```go v1 := make([]int,1,3) fmt.Println(len(v1),cap(v1)) //获取长度和容量 ``` #### 6.3.2 索引 - 根据长度去索引取值 - 不要根据容量索引去取值 ```go v1 := []string{"alex","lijie","oldboy"} v1[0] v1[1] v1[2] v2 := make([]int,2,5) v2[0] v2[1] v2[2] //报错 //根据索引修改值 v2[0] = 999 ``` #### 6.3.3 切片 - 切片的切片不会创建新的切片,还是引用原来的切片,只是切片的内存地址起始位置变了 ```go v1 := make([]int{0,1,2,3,4,5}) v2 = v1[1:3] v3 = v1[1:] v4 = v1[:4] ``` #### 6.3.4 追加 - 追加:`append()` ```go v1 := make([]int{0,1,2}) v2 = append(v1,3) v3 = append(v1,3,4,5) v4 = append(v1, []int{100,200,300}...) ``` #### 6.3.5 删除(不建议) - 删除是通过append()构造出来的 ```go v1 := make([]int{11,22,33,44,55,66}) delete_index = 2 result := append(v1[:delete_index],v1[delete_index+1:]...) fmt.Println(result) // [11 22 44 55 66] fmt.Println(v1) // [11 22 44 55 66 66] ``` 使用切片的时候一般不适用删除 - 效率低 - 修改了远切片的内容并且覆盖了 - 删除的时候用链表 #### 6.3.6 插入(不建议) ```go v1 := int[]{11,22,33,44,55,66} insertIndex = 3 //在3地方插入99 result = make([]int,len(v1)+1) result = append(result,v1[:insertIndex]) result = append(99) result = append(result,v1[insertIndex:]) fmt.Println(result) ``` 使用切片的时候一般不适用插入 - 效率低 - 出错 - 删除的时候用链表 #### 6.3.7 循环 - range循环 - index循环 ```go func main(){ v1 := []int{11,22,33,44,55,66} for i:=0;i