Loading... ## 编写go代码 1、新建文件,app.go ``` package main import "fmt" func main(){ fmt.Println("hello world"); } ``` 2、执行代码:go run app.go 3、编译代码:go build ## 基础 ##### 1.包(package) - 同目录下,文件的包名必须保持相同 - 包名可以不与文件夹同名,但建议同名 - 方法名首字母小写为私有方法,大写为公共方法 ##### 2.注释 - 单行注释 // - 多行注释 /* */ ##### 3、数据类型 整型 字符串 布尔类型 ##### 4.变量 【要求】变量名必须只包含:字母、数字、下划线 ```go // 变量 var name string = "luffy"; var age int = 18; var flag bool = true; // 常量 ``` 【要求】内部关键词禁用 ```go var var string = "aaa"; 错误 ``` 【要求】不允许数字开头 ```go var 1s int = 1; 错误 ``` ###### 变量简写 ```go var name string = "邓紫棋" var name = "邓紫棋" name:="邓紫棋" //推荐 // 先声明再赋值 var name,message,data string name = "邓紫棋" message = "中奖了" data = "5000W" ``` ###### 因式分解 ```go var ( name = "邓紫棋" age = 18 hobby = "大保健" salary = 100000 gender string // string默认不赋值是"" length int // int默认不赋值是0 isDel bool // boolean默认不赋值是false ) fmt.println(name,age,hobby,salary,gender) ``` ###### 变量的作用域 【规定】全局变量不允许使用缩写 ```go // 正确 var name string = "邓紫棋" // 错误 name:="邓紫棋" // 可以使用因式分解 var ( name = "邓紫棋" age = 18 ) ``` ###### 赋值及内存相关 ```go // 使用int、string、boolean这三种数据类型,遇到变量的赋值则会拷贝一份。【值类型】 name:="邓紫棋" //内存0001 nickname := name. //内存0002 ``` ##### 5.常量 ```go // 定义常量 const name string = "邓紫棋" const age = 18 // 常量不允许修改 // 可以用因式分解 const ( v1 = 123 v2 = 456 ) ``` ###### iota ```go const ( v1 = iota v2 v3 v4 v5 ) fmt.Println(v1,v2,v3,v4,v5) // 0 1 2 3 4 // ============================== const ( v1 = iota +1 v2 v3 v4 v5 ) fmt.Println(v1,v2,v3,v4,v5) // 1 2 3 4 5 // ============================== const ( v1 = iota +1 _ v2 v3 v4 v5 ) fmt.Println(v1,v2,v3,v4,v5) // 1 3 4 5 6 ``` ##### 6.输入 用户输入数据,完成交互 - fmt.Scan("param") ```go // 示例 var name string fmt.Println("请输入用户名") fmt.Scan($name) fmt.Println(name) ``` ##### 7.条件语句 ###### 最基本 ```go if 条件 { 成立后执行 }else{ 不成立后执行 } if username=="alex" && password =="123456" { fmt.Println("登录成功") } ``` ###### 多条件判断 ```go if length<1 { }else if length <10{ }else{ } ``` ###### 嵌套判断 ```go // type 1用户 2管理员 // status 0正常 1封禁 if type==1{ if status == 1{ fmt.Println("被封禁了") } }else if type == 2{ } ``` ##### 8.switch语句 ```go switch 1+1 { case 1: fmt.Println("1") case 2: fmt.Println("2") case 3: fmt.Println("3") default: fmt.Println("都不满足") } // 数据类型必须一致 ``` ##### 9.for循环 ```go // 死循环 for { } // 条件循环 for number < 5 { time.Sleep(time.Second*1) } // 布尔循环 for flag { } // 变量条件 for i:=1;i<10;i++ { } // continue 中断本次循环 进入下次循环 // break 跳出循环 打断循环 ``` ###### for打标签 ```go f1:for i:=1;i<10;i++ { for j:=1;j<5;j++{ if j==3 { continue f1 } } } ``` ##### 10.goto语句 ```go' if name=='a'{ goto a } if name=='b'{ goto b } a: xxxxx b: xxxxx ``` ##### 11.字符串格式化 ```go name:="alex" address:="青岛" action:="开会" fmt.Sprintf("我叫%s,我在%s,我正在%s",name,address,action) ``` ## 数据类型 #### 整形 ##### int类型范围 int8(-128,127) int16(-32768,32767) int32(-2147483648,2147483647) int64(-9223372036854775808,9223372036854775807) ##### 1.整形之间的转换 ```go var v1 int8 = 10 var v2 int16 = 18 v3 := int16(v1)+v2 ``` ##### 2.整形与字符串的转换 ###### 整形转字符串 ```go v1 := 19 // 整形转字符串 result := strconv.Itoa(v1) // result打印出来后是字符串 var v2 int8 = 17 data := strconv.Itoa(int(v2)) fmt.Println(data,reflect.TypeOf(data)) ``` ###### 字符串转整形 ```go // 字符串转换成整形 v1 := "16" result := strconv.Atoi(v1); // 如果是字符串:英文、汉字等,则转换失败,会转成0 ``` ##### 3.整形转换为二进制 ```go v1 := 5 // 十进制转换为二进制 r1 := strconv.FormatInt(int64(v1),2) // 十进制转换为八进制 r2 := strconv.FormatInt(int64(v1),8) // 十进制转换为16进制 r3 := strconv.FormatInt(int64(v1),16) ``` ```go // 二进制转换为十进制 data := "1001000101" // 0代表默认的int64,8就是int8 strconv.ParseInt(data,2,0) ``` ##### 4.指针&&nil&&声明变量&&new ```go // 指针 var v3 *int v4 := new(int) // new用于创建内存并进行内部数据的初始化,并返回一个指针类型 // nil 代表空置 ``` ##### 5.超大整形 big.Int ```go // 创建超大整形 var v1 big.Int v1.SetInt64(1990) v1.SetString("901231231231223",10) ``` ```go // 基本的加减乘除 n1 := new(big.Int) n1.SetInt64(89) n2 := new(big.Int) n2.SetInt64(999) result := new(big.Int) // 加 result.Add(n1,n2) // 减 result.Sub(n1,n2) // 乘 result.Mul(v1,v2) // 除(只能得到商) result.Div(v1,v2) // 除(得商和余数,余数是minder) minder := new(big.Int) result.DivMod(v1,v2,minder) fmt.Println(result,minder) // 【推荐】转换成字符串 result.String() // 转成整形 result.Int64() ``` ```go // 简写 n1 := big.NewInt(89) ``` ###### 建议 - 尽量使用new方式去初始化并返回一个指针类型的方式。 - 易错的点(int类型和*int类型,后者是指针) #### 浮点型 ```go // 创建浮点数,默认是float64 var v1 float32 v1 = 3.14 v2 := 99.9 v3 := float64(v1)+v2 ``` 浮点型是非精确的 ```go v4 := 0.1 v5 := 0.2 result := v4+v5 // 打印result等于0.3000000000000000004 ``` ##### decimal(精确小数处理方法) Go内置没有decimal,需要暗转给第三方包 安装第三方包 ```go go get github.com/shopspring/decimal ``` 导入decimal包 ```go import ( "fmt", "github.com/shopspring/decimal" ) ``` 处理精确小数 ```go decimal.NewFromFloat(3.4626) // 保留小数点后1位(四舍五入) var data1 = price.Round(1) // 保留小数点后1位(不四舍五入) var data2 = price.Truncate(1) // 输出 3.5 3.4 ``` #### 布尔型 ```go // 字符串转布尔值 strconv.ParseBool("stirng") // 布尔值转字符串 strconv.FormatBool(false) ``` #### 字符串 ##### 底层原理 计算机中所有的操作和数据最终都是二进制,即:101010100011 Go语言中的字符串是uft-8的编码 ```go // 获取字符串长度(字节) name := "邓紫棋" len(name) // 9 // 获取字符长度(总长度) utf8.RuneCountInString(name) //3 // 字符串转换为字节集合 byteSet := []byte(name) // 字节集合转换为字符串 byteList = []byte{230,277,166,230,187,178,233,189,144} String := string(byteList) // 将字符换转换为unicode字符集码点的集合 tempSet = []rune(name) // [27652 19829 12239] // rune集合转换为字符串 string(tempSet) ``` ##### 常见的15个功能 ```go name := "邓紫棋" // 获取字节长度 9 fmt.Println(len(name)) //获取字符长度 3 fmt.Println(utf8.RuneCountInString(name)) //是否以XXX开头 strings.HasPrefix(name, "邓") //是否以XXX结尾 strings.HasSuffix(name, "棋") //是否包含 strings.Contains(name, "邓") //转大写 strings.ToUpper(name) //转小写 strings.ToLower(name) //去除左边 strings.TrimLeft(name, "邓") //去除右边 strings.TrimRight(name, "棋") //去除两边 strings.Trim(name, "w") //替换 查到邓替换成DENG,从左到右数第一个 strings.Replace(name, "邓", "DENG", 1) //替换 查到邓替换成DENG,从左到右数第二个 strings.Replace(name, "邓", "DENG", 2) //替换 查到邓替换成DENG,全部替换 strings.Replace(name, "邓", "DENG", -1) //分割 strings.Split(name, "紫") //拼接 string2 := []string{"我爱", "中国"} string2Result := strings.Join(string2, "-") fmt.Println(string2Result) ``` ##### 索引切片和循环 ```go name := "邓紫棋" // 根据索引获取字节 name[0] // 切片获取字节区间 name[0:3] ``` #### 数组 ##### 基本用法 数组,定长且所有数据的类型相同的数据集合 ```go // 内部已开辟了3个空间,都是0 var number [3]int number[0] = 999 number[1] = 666 number[2] = 333 ``` ```go // 声明+赋值 var names = [2]string{"邓紫棋","林俊杰"} ``` ```go // 声明+赋值+指定位置 var ages = [3]int{0:87,1:29,2:11} ``` ```go // 省略个数 var ages = [...]int{0:87,2:11} ``` ##### 数组的内存管理 知识点: - 数组的内存都是连续的 - 数组的内存地址实际上是数组第一个元素的内存地址 - 每个字符串的内部存储都是len+str ##### 可变和拷贝 可变,数组的元素可以被更改(长度和类型不可以修改) 变量赋值时,会重新拷贝一份 ```go name1 := [2]string{"邓紫棋","林俊杰"} name2 := name1 name1[0] = "周杰伦" fmt.Println(name1) // ["周杰伦","林俊杰"] fmt.Println(name2) // ["邓紫棋","林俊杰"] ``` ##### 长度、索引、切片、循环 ```go name1 := [2]string{"邓紫棋","林俊杰"} // 长度 len(name1) //2 // 索引 name[0] //邓紫棋 // 切片 numbers := [3]int32{11,22,33} numbers[0:2] //[11 22] 从下标0开始 大于等于0,小于2(不包括2) // 循环 for i:=0;i<len(numbers);i++{ } // for range 循环 for key,item:=range numbers{ // key可写可不写 } ``` ##### 数组嵌套(二维数组) ```go // 声明一个二维数组 var array := [2][3]int // [[0,0,0],[1,1,1]] // 赋值 array[0] = [3]int{2,2,2} //[[2,2,2],[1,1,1]] // 赋值数组中的数据 array[1][1] = 666 //[[2,2,2],[1,666,1]] // 直接声明 nestData := [2][3]int{[3]int{11,22,33},[3]int{44,55,66}} ``` #### 切片 ##### 1.基础 切片就是动态数组 ###### 1.1创建切片 ```go var numbers []int // make只用于切片、字典、channel var users = make([]int,2,5) // 2数据长度,5是容量 var data = []int{11,22,33} var v1 = new([]int) // 返回切片指针 var v2 *[]int // 返回nil ``` ###### 1.2自动扩容 ```go v1 := make([]int,1,3) // 向v1切片插入66 v2 := append(v1,66) ``` ###### 1.3常见操作 ```go // 长度和容量 var data = []int{11,22,33} len(data) //长度 cap(data) //容量 // 索引 v1 := []string{"邓紫棋","周杰伦","林俊杰"} v1[0] v1[1] v1[2] v2 := make([]int,2,5) v2[0] v2[1] v2[2] //报错 // 切片 var data = []int{11,22,33,44,55,66} v1[1:3] // [22,33] 从下标1开始 大于等于1,小于3(不包括3) v1[1:] // 第二个值不写代表一直到最后[22,33,44,55,66] v1[:3] // 第一个值不写,代表从第一个开始[11,22,33] // 注意:通过切片获取出的数据与原数据的内存地址保持一致 // 追加 v1 := []int{11,22,33} v2 := append(v1,44) v3 := append(v1,55,66,77,88) v4 := append(v1,[]int{888,999,000}...) // 删除 var data = []int{11,22,33,44,55,66} deleteIndex := 2 result := append(data[:deleteIndex],data[deleteIndex+1:]...) // 插入 var data = []int{11,22,33,44,55,66} insertIndex := 3 // 在索引3的位置插入99 result := make([]int,0,len(data)+1) result := append(data,data[:insertIndex]...) result := append(data,99) result := append(data,data[insertIndex:]...) ``` ###### 1.4变量赋值  #### map ###### 1.1基础 Map 的特点: - 键不能重复 - 键必须可哈希(目前已学习数据类型中可哈希的有:int/bool/float/string/array) - 无序 ```go { "age":18, "name":"邓紫棋", "email":"1111@qq.com" } ``` ###### 1.2创建map ```go // 创建map userInfo := map[string]string{"name":"邓紫棋","age":"18"} // 查询 userInfo["name"] // 邓紫棋 // 赋值 userInfo["age"] = "20" ``` ```go // 使用make方式创建map data := make(map[int]int) data[100] = 998 data[200] = 999 ``` ```go // 声明,内部为nil,空定义无法赋值 var row map[string]int row["name"] = 666 //报错 // ✅正确方式:整体赋值 row = data ``` ```go // 声明,nil,返回指针 value := new(map[string]int) value["k1"] = 123 // 报错 data := make(map[string]int) data["100"] = 998 data["200"] = 999 value = &data ``` 注意:键不重复 & 键必须可哈希(int/bool/float/string/array) ```go v1 := make(map[[2]int]float32) v1[[2]int{1,1}] = 1.6 v1[[2]int{1,2}] = 1.4 v2 := make(map[[2]int][3]string) v2[[2]int{1,1}] = [3]string{"邓紫棋","周杰伦","林俊杰"} ``` ###### 1.3常用操作 长度和容量 ```go data := map[string]string{"n1":"邓紫棋","n2":"周杰伦"} val := len(data) // 2 v2 := cap(data) //报错 ``` 嵌套 ```go v1 := make(map[string]int) v2 := make(map[string]string) v3 := make(map[string][2]int) v4 := make(map[string][]int) v5 := make(map[string]...) //值任意类型 v6 := make(map[string]map[int]int) ``` ```go v7 := make(map[string][2]map[string]string) v7["n1"] = [2]map[string]string{map[string]...{"name":"邓紫棋","age":20},map[string]...{"name":"周杰伦","age":56}} ``` 增删改查 ```go data := map[string]string{"n1":"111","n2":"222"} // 增 data["n3"] = "333" // 删 delete(data,"n2") // 改 data["n3"] = "3333" // 查 data["n3"] ``` ###### 1.4扩容 在向map中添加数据时,当达到某个条件,则会引发字典扩容。 扩容条件: - map中数据总个数/桶个数>6.5,引发翻倍扩容。 - 使用了太多的溢出桶时(溢出桶使用的太多会导致map处理速度降低)。 - B<=15,民使用的溢出桶个数>=2的B次方时,引发等量扩容。 - B>15,已使用的溢出桶个数>=2的15次方时,引发等量扩容。 ### 指针 应用场景: - 希望多个变量的值同步修改,需要用指针 - 执行函数,直接传的话函数内会拷贝一份;如果传入指针,则函数内会根据原传入值发生改变而改变。 ## 结构体 ### 什么是结构体? > 结构体是一个复合类型,用于表示一组数据 > > 结构体有一系列属性组成,每个属性都有自己的类型和值 ```go // 定义 type Person struct{ name string age int email string } // 初始化 p1 := Person("周杰伦",50,"1111@qq.com") // 从结构体取值 p1.name p1.age ... // 为结构体重新赋值 p1.name = "邓紫棋" ``` ```go // 结构体格式 type 结构体名称 struct { 字段名:类型 } ``` ### 结构体的定义 最常见 ```go type Person struct{ name string age int email string } ``` 缩写 ```go type Address struct{ city,status string age int } ``` 嵌套 ```go type Person struct{ name string age int address Address } ``` 匿名字段 ```go type Person struct{ name string age int Address // 匿名字段,默认为 Address Address } ``` ### 初始化结构体 ```go type Person struct{ name string age int hobby []string } // 方式1:先后顺序 var p1 = Person{"周杰伦",20,[]string{"篮球","足球"}} // 方式2:关键字 var p2 = Person{"name":"周杰伦","age":20,"hobby":[]string{"篮球","足球"}} // 方式3:先声明后赋值 var p3 Person p3.name = "周杰伦" p3.age = "age" p3.hobby = []string{"篮球","足球"} ``` 包含结构体的赋值 ```go type Address struct{ city,status string age int } type Person struct{ name string age int Address // 匿名字段,默认为 Address Address } p1 := Person{"周杰伦",20,Address{"青岛市","正常",20}} ``` ### 结构体指针 ```go p2:=&Person{"邓紫棋",20} var p3 *Person = new(Person) ``` ### 复制和拷贝 ```go p1 := Person{"name":"周杰伦","age":20} p2 := p1 // p2是复制拷贝了一份p1 ``` ```go // 如果是指针赋值 p1 := &Person("周杰伦",18) p2 := p2 // 指针内存地址不同,但是最终指向的是相同的,修改其中任何一个值 其他的都会发生改变 ``` ### 结构体标签 ```go type Person struct{ name string "姓名" age int "年龄" email string "邮箱" } // 获取标签 p1 := Person{name:"邓紫棋",age:20,email:"1111@qq.com"} p1Type := reflect.Typeof(p1) // 方式1: field1 := p1Type.Field(0) // 方式2: field,_ := p1Type.FieldByName("blog") ``` ## 函数 ##### 定义函数 ```go // params 传入参数 // bool 返回值 func action(params string) bool { // 方法 return true } func main(){ // 执行函数 action("params") } ``` 命名注意:必须是字母数字下划线且数字不能开头,建议驼峰写法。 ##### 参数 ```go func add(num1 int,num2 int) (int,bool){ result := num2+num1 return result,true } func main(){ data,flag := add(1,8) fmt.Println(data,flag) } >>> 输出: 9 true ``` ```go // 传参(传函数) func proxy(data int,exec func(int) (int,bool)) int { } ``` ```go // 变长参数 只能存在一次,并且只能放在最后 func do(num ...int) int { } ``` ##### 匿名函数 ```go func main(){ v1 := func(n1 int,n2 int) int { return n1+n2 } v2 := v1(222,333) } ``` ##### 闭包 ```go // 简单描述就是提前把变量封锁在函数里,不会导致后续方法执行的时候 变量发生变化 导致函数结果错误 ``` 最后修改:2024 年 12 月 05 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 如果觉得我的文章对你有用,请随意赞赏
3 条评论
这篇文章提供了宝贵的经验和见解,对读者有很大的启发和帮助。
内容的丰富性和深度让人仿佛置身于知识的海洋,受益匪浅。
建议多用口语化表达,拉近与读者距离。