go语言数据类型
一.Go 语言有四大显著特点:
	高效性:编译与运行效率高。
	并发性:原生支持并发编程。
	简洁性:编程风格简洁直接,代码可读性与可维护性高。
	跨平台性:程序能在 Windows、Linux、Mac OS 等多系统运行。
二.go的包:package
	1.main:主函数
	2.fmt:输出     	 #fmt.Println()
	3.rand:随机数  
		rand.Intn(n) #生成0-n之间的随机数
三.go的工具链组件: import 
	1.go mod init+自定义名称	#初始化项目,生成项目文件
	2.go run + 文件		#编译并执行文件 	
	3.go build       		#编译,将当前目录中的.go文件编译为可执行文件
	 	go build -o demo01_app demo01.go
		//-o demo01_app 指定可执行文件的名字
	4.go doc 组件名称            #查看组件的文档
	
四.变量(var):变量申明后必须要使用
	1.声明赋值:var  变量名1,变量名2 数据类型 = a,b
			var name,name2 string =a,b
		(1)声明多个不同类型的变量:
			var (
			    name    string
			    age     int
			    address string
			)
	2.短变量:不需要申明类型,系统自动判断类型
			格式: name := "jack" // 字符串类型的变量。
	3.匿名变量:a, b, _ := 1, 2, 3:表示第三个值不使用
	
	4.交换变量
			num1, num2 := 25, 36
			nam1, num2 = num2, num1
五.常量(const):不允许重新赋值
	1.声明赋值:const name string = "Jack"
		声明多个常量:
		const(
			a int=1
			b string ="aa"
		)
	2.iota:声明无类型的"整数"序数(等差数列)
		const (
			a = iota
			b
			c
		)
六.输出和输入
	格式化输出:fmt.Printf()
		1.%v   #任意类型
		2.%s   #字符型
		3.%d   #整型
		4.%.2f #浮点:保留两位小数
		5.%t   #布尔值
		6.%T   #输出类型
		7.%c	 #编码转换,输出对应字符
	获取键盘输入:
		fmt.Scan(&a,&b),控制台空格间隔,输完参数自动结束,&为固定的绑定变量值的符号
		fmt.Scanln(&a,&b),控制台空格间隔,输完参数回车结束
七.数据类型
1.基本数据类型
	(1)整型
		有符号整型(分正负) int8/16/32/64,默认由操作系统决定 [-32768, 32767]
		无符号整型(不分正负) uint8/16/32/64	 [0, 65535]
	(2)浮点
		float32	32位浮点数
		float64	64位浮点数(短变量默认类型)
	(3)布尔类型
		bool	true为真值,false为假值
		var b1 bool = true
	(4)字符串类型
		1)字符串
		string	字符串,字符串可以用双引号""或反引号``来表示
		str := "Hello, World!"
		multilineStr := `       //可以换行
		    This is a
		    multiline string.
		`
		2)字符串的拼接:+
			str1 := "Hello, "
			str2 := "World!"
			str = str1+str2
	
		3)字符串长度,单位是字节,英文占一个字节,汉字占三个字节:len
			str := "Hello, World!"
			length := len(str) 
	
		4)字符串索引:[],输出ascii码,的值用string()转回
			str := "Hello世界"
			firstChar := str[0]           
			secondChar := str[5]   #汉字占三个字节,这样只取出一个字节
			fmt.Println(firstChar, secondChar) // 输出 '72' 和 '228'
			// 编码转换
			fmt.Println(string(firstChar), string(secondChar)
	
		5)字符串切片:可以取出汉字的内容,按照字节进行计数
			str[start:end]:从start到end(不包括end)。
			str[:]:获取字符串的完整副本
			str := "Hello世界"
			fmt.Println(str2[5:8]) // "世"
	(5)字符型:可输出中文完整的ascii编码,使用string()可以转换,0到255
		1)byte,使用单引号包括一个字符,相当于uint8
			var a byte = 'a' 
			fmt.Println(a)  // 97,输出ASCII编码值
		
		2)rune,相当于int32,0到65535
			var b rune = '中'
			fmt.Println(b)  // 20013
	(6) \转义字符
		\n   换行符号
		\t   横向制表符号(多空格)
		\b   回退符号
		\f   换页符号
	(7)零值:一个类型的空值或者说默认值更为准确。
		var i int  // 默认为0
		var s8 string  // 默认为""
		var b3 bool  // 默认为false
2.各种引用数据类型
	1.数组
		1.数组初始化
		(1)初始化一个长度为5的整型数组
			var nums [5]int
	
			names = [3]string{"1","2","3"}
	
			for i := 0; i < index; i++ {
	        		newArr[i] = arr[i]
	    		}
		(2)也可以用元素初始化
			nums := [5]int{1, 2, 3}
		(3)自动设置长度
			nums := [...]int{3, 8, 7, 12}
	
		(1)下标访问:names[i]
		(2)切片访问:names[n:m],不包括m,从0开始的话,可以省略
			names[:m],names[0:],names[:]
		(3)数组长度:len(数组)
		(4)遍历数组,for循环的简化版
			for key, value := range names {
			    fmt.Println(key, value)
			}
		(5)反转数组:
			func reverseArray(arr [6]int) [6]int {
			    length := len(arr)
			    for i := 0; i < length/2; i++ {
			        arr[i], arr[length-i-1] = arr[length-i-1], arr[i]
			    }
			    return arr
			}
			
			func main() {
			    arr := [6]int{10, 20, 30, 40, 50, 60}
			    reversed := reverseArray(arr)
			    fmt.Println("反转后的数组:", reversed)
			}
		2.二维数组
			1)// 初始化一个 2 行 3 列的二维数组
			    var arr [2][3]int = [2][3]int{  #本质操作行和列
			        {1, 2, 3},
			        {4, 5, 6},
			    }
		
			2)// 使用 ... 自动推断行数
			    arr := [...][3]int{
			        {1, 2, 3},
			        {4, 5, 6},
			    }
			    fmt.Println(arr)
			3) //遍历二维数组,相加列
				func main() {
				    // 定义命令行参数
					arr :=[2][2]int{
						{1,2},
						{4,3},
					}
					res :=make([]int,len(arr[0]))
					for k,_ :=range arr[0]{ //列
						sum :=0
						for k1,_ :=range arr{ //行
							fmt.Println(arr[k1][k])
							sum = sum+arr[k1][k]
						}
						res[k] = sum
					}
					fmt.Println(res)	
				}
	2.切片:和数组相比就是没有设置长度
		(1)切片的初始化:和数组相比就是没有设置长度
			s := []int{1, 2, 3, 4, 5} // 创建一个包含5个元素的切片
			s := make([]int, 5, 10) // 创建类型为[]int,长度为5,最大容量为10的切片
			
		(2)切片的长度和容量
			len(slice),cap(slice)   //容量第一次成倍扩容,后面一个一个扩容
	
		(3)子切片
			slice[startIndex:endIndex] //子切片的内容改变,父切片的内容也会改变
	
		(4)切片增加元素
			s = []int{1, 2, 3, 4,  5}
			s = append(s, 6, 7, 8) // 向切片中添加元素,返回新的切片
	
		(5)元素展开 
			s1 :=sp[:2]
		 	s2 :=sp[3:]
		 	s := append(s1,s2...)  //s2...元素展开,在append函数使用
		 	fmt.Println(s)
		
		(6)复制拷贝切片
			当需要一个独立副本时,可以使用内置的copy函数来实现
			num1 :=[]int{1,2,3}
			num2 :=make([]int,len(num1))
			copy(目标切片, 源切片)
		
		(7)字节切片:[]byte,字符串每个字符取出是字节,占用 1 个字节的内存空间。
				
		8)字符串-->转字符切片
                    var str string
			runes :=[]rune(s)
		  字符切片(ascci)-->转字符串,占用 4 个字节的内存空间
			string(runes)
	3.指针类型,指向一个内存地址
		(1)指针的申明
			var p *int //指针类型,p表示地址
			*p         //*取值
			 p = &a    //&取地址
		
		(2)new函数:分配一个内存
			p :=new(int)
			*p =100
	
	
	4.映射(map)类型:关联键和值的数据结构(无序),查找灵活
	
		(1)可扩展make初始化
			s :=make(map[string]int) //map[键类型][值类型]
			赋值:s["1"]=1
		 --
			s :=map[string] int{
				"key":   value,
		        	"Bob":   50000,
		        	"Charlie": 60000,	
				}
		(2)访问值,通过键得到值
			v :=s[key]
		
		(3)删除元素
			delete(映射名字(变量值),“键”)
	
		(4)循环输出
			for key,value :=range 映射的变量名字{
				fmt.Println(key,value)
			}
			
	5.结构体类型(struct)
		(1)语法结构,定义在main之外
			type 结构体名 struct {
			    字段名1 类型1
			    字段名2 类型2
			    ...
			}
			type Person struct { //首字母大写,导包使用
			    Name string
			    Age  int
			    City string
			}
	
		(2)初始化结构体
			var p Person
			p.Name = "Alice"
			p.Age = 30
			p.City = "Beijing"
		   --简化初始化
			s := Person{
				Name: "Bob",
				Age: 25, 
		             City: "Shanghai"
			     }
	
			s := Person{
				"Bob",
	                    25,
	                    "Shanghai"
		     }
		
		(4)匿名结构体
			person := struct {
			    Name string
			    Age  int
			}{
			    Name: "Charlie",
			    Age:  28,
			}
		
		(5)切片和map在结构体中的初始化
				p2.A_name=[]string{"aa","bb"}
				p2.Ck=map[string]int{"name":1}
	
	6.Json类型:是一种轻量级的数据交换格式
		{
		    "name": "Alice",
		    "age": 20,
		    "is_married": false,
		    "like": ["red", "blue", "purple"],
		    "phone": null
		}
		
	
		(1)序列化:json.Marshal,go中的数据转为json格式,序列化。json格式转为go中的数据格式,反序列化	
		设置标签:结构体的标签对应JSON对象的键,也可以不设置使用默认的
			type Person struct {
			    Name    string            `json:"name"`
			    Age     int               `json:"age"`
			    Like    []string          `json:"like"`
			    Address map[string]string `json:"address"`
			}
			// 序列化
			jsonData, err := json.Marshal(p1)
			
			if err != nil {
			    fmt.Println(err)
			}
	
	
		(2)反序列化:json.Unmarshal,将JSON格式的字节切片解码为Go语言结构体。
			// 反序列化
			var p2 Person
			err2 := json.Unmarshal(jsonData, &p2)
			if err != nil {
			    fmt.Println(err2)
			}
			fmt.Println(p2)
找各种包:studygolang--->标准库中文版,
八.字符串操作
	(1)遍历:英文,汉字可能会出现乱码,因为一个汉字可能占多个字节。
		str := "Hello"
		for i := 0; i < len(str); i++ {
		    fmt.Printf("%c ", str[i])
		}
		fmt.Println()
		
		按字符(rune)遍历
		优点: 能正确处理 UTF-8 编码的多字节字符,避免乱码。
		str := "Hello, 世界"
		for _, char := range str {  //range 遍历数据类型,大多都返回key,value
		    fmt.Printf("%c ", char) 
		}
	
	(2)Contains/Index查找字符串
		1)strings.Contains(“源字符串”, “目标字符串”) bool: 判断字符串 s 是否包含子串 substr。
			text := "I love programming in Go!"
			fmt.Println(strings.Contains(text, "Go")) // 输出 true
		2)strings.Index(“源字符串”, “目标字符串”) int: 返回子串 substr 在 s 中首次出现的索引。
			text := "hello, world"
			index := strings.Index(text, "world")
			fmt.Println(index) // 输出 7
	(3)Replace替换字符串
		strings.Replace(“源字符串”, old, new,替换次数) //将 s 中的前 n 个 old 子串替换为 new 子串。
	(4)Split分割字符串:输出为切片
		strings.Split(“源字符串”,"分隔符") //以“分隔符”将 s 分割成多个子串。
	(5)切片-->字符串:Join
		strings.Join(“源字符串切片”, “连接符号”) //将字符串切片 a 中的元素用 sep 连接起来。
	(6)大小写转换
		strings.ToLower(“字符串”)  // 将 s 中的所有字母转换为小写。
		strings.ToUpper(“字符串”)  //将 s 中的所有字母转换为大写。
		strings.TrimSpace(“字符串”) //去除 s 首尾的空格。
九.数据类型转换
	整型和浮点的转换:
		var a int8 = 6
		int16/float64(a) 
		
	字符串转换:
		1)fmt.Sprintf("%d", a):其它类型转字符串,只格式化,不输出
			var a int = 20
			var stra string   //转换的类型
			stra = fmt.Sprintf("%d", a) //格式化输出转换
			fmt.Printf("stra type is %T, value is %v \n", stra, stra)
		
		2)fmt.Sprintf: //不同类型的数据拼接
			var str string = "aa"
			var f1 float32 = 12.2
			var b1 bool = true
			a := fmt.Sprintf("商品标题:%s 价格:%f 是否在售:%t\n",str,f1,b1)
			fmt.Printf(a)
		3)strconv:实现基本数据类型和字符串之间的转换
			字符串和整型相互转换
				strconv.Atoi(str) #字符串转整型
				strconv.Itoa(int) #整型转字符串
			字符串和浮点形转换	
				strconv.ParseFloat(str,64) #字符串转浮点
				strconv,FormatFloat(num,'f',2,64) #浮点转字符串(要转换的浮点型,输出浮点形,保留2位,64位的)
			字符串和布尔转换
				strconv.ParseBool(str)  #字符串转布尔
				strconv.FormatBool(b)   #布尔转字符串
		4)字符串-->转字符切片
                    var str string
			runes :=[]rune(s)
		  字符切片(ascci)-->转字符串
			string(runes)
		
		5)strings.Join:"字符串"切片-->转字符串
    		  result := strings.Join(strSlice, ",")
		
练习:
// 创建一个映射,键为学生的姓名(字符串类型),值为一个自定义的 Student 结构体,
// 该结构体包含 Age(整数类型)和 Scores(整数切片类型,存储学生的多门课程成绩)两个字段。
// 实现以下功能:
// - 向映射中添加至少 3 个学生的信息。
// - 计算并输出每个学生的平均成绩。
// - 找出平均成绩最高的学生,并输出其姓名和平均成绩。
type Student struct{
	Age int
	Scores []int
}
func main() {
	smap :=make(map[string]Student)
	smap["name1"] =Student{
		Age:11,
		Scores: []int{1,3},
	}
	smap["name2"] =Student{
		Age:22,
		Scores: []int{2,4},
	}
	smap["name3"] =Student{
		Age:33,
		Scores: []int{4,6},
	}
	// avg :=make([]int,0)
	// fmt.Println(smap)
	hs :=""
	hc :=0
	for k,_ :=range smap{
		sum :=0
		for _,v1 :=range smap[k].Scores{
			sum =sum+v1	
		}
		// avg =append(avg,sum/len(smap[k].Scores))
		fmt.Printf("%s,%d\n",k,sum/len(smap[k].Scores))
		if hc < sum/len(smap[k].Scores){
			hc = sum/len(smap[k].Scores)
			hs = k
		}
	}
	fmt.Println(hs,hc)
}		
			
 
一.Go 语言有四大显著特点:
     高效性:编译与运行效率高。
     并发性:原生支持并发编程。
     简洁性:编程风格简洁直接,代码可读性与可维护性高。
     跨平台性:程序能在 Windows、Linux、Mac OS 等多系统运行。
 二.go的包:package
     1.main:主函数
     2.fmt:输出          #fmt.Println()
     3.rand:随机数  
         rand.Intn(n) #生成0-n之间的随机数
三.go的工具链组件: import 
     1.go mod init+自定义名称    #初始化项目,生成项目文件
     2.go run + 文件        #编译并执行文件     
     3.go build               #编译,将当前目录中的.go文件编译为可执行文件
          go build -o demo01_app demo01.go
         //-o demo01_app 指定可执行文件的名字
     4.go doc 组件名称            #查看组件的文档
     
四.变量(var):变量申明后必须要使用
     1.声明赋值:var  变量名1,变量名2 数据类型 = a,b
             var name,name2 string =a,b
         (1)声明多个不同类型的变量:
             var (
                 name    string
                 age     int
                 address string
             )
     2.短变量:不需要申明类型,系统自动判断类型
             格式: name := "jack" // 字符串类型的变量。
    3.匿名变量:a, b, _ := 1, 2, 3:表示第三个值不使用
     
     4.交换变量
             num1, num2 := 25, 36
             nam1, num2 = num2, num1
五.常量(const):不允许重新赋值
    1.声明赋值:const name string = "Jack"
         声明多个常量:
         const(
             a int=1
             b string ="aa"
         )
    2.iota:声明无类型的"整数"序数(等差数列)
         const (
             a = iota
             b
             c
         )
六.输出和输入
     格式化输出:fmt.Printf()
         1.%v   #任意类型
         2.%s   #字符型
         3.%d   #整型
         4.%.2f #浮点:保留两位小数
         5.%t   #布尔值
         6.%T   #输出类型
         7.%c     #编码转换,输出对应字符
     获取键盘输入:
         fmt.Scan(&a,&b),控制台空格间隔,输完参数自动结束,&为固定的绑定变量值的符号
         fmt.Scanln(&a,&b),控制台空格间隔,输完参数回车结束
 七.数据类型
 1.基本数据类型
     (1)整型
         有符号整型(分正负) int8/16/32/64,默认由操作系统决定 [-32768, 32767]
         无符号整型(不分正负) uint8/16/32/64     [0, 65535]
     (2)浮点
         float32    32位浮点数
         float64    64位浮点数(短变量默认类型)
    (3)布尔类型
         bool    true为真值,false为假值
         var b1 bool = true
    (4)字符串类型
         1)字符串
         string    字符串,字符串可以用双引号""或反引号``来表示
         str := "Hello, World!"
         multilineStr := `       //可以换行
             This is a
             multiline string.
         `
         2)字符串的拼接:+
             str1 := "Hello, "
             str2 := "World!"
             str = str1+str2
     
         3)字符串长度,单位是字节,英文占一个字节,汉字占三个字节:len
             str := "Hello, World!"
             length := len(str) 
     
         4)字符串索引:[],输出ascii码,的值用string()转回
             str := "Hello世界"
             firstChar := str[0]           
             secondChar := str[5]   #汉字占三个字节,这样只取出一个字节
             fmt.Println(firstChar, secondChar) // 输出 '72' 和 '228'
             // 编码转换
             fmt.Println(string(firstChar), string(secondChar)
     
         5)字符串切片:可以取出汉字的内容,按照字节进行计数
             str[start:end]:从start到end(不包括end)。
             str[:]:获取字符串的完整副本
             str := "Hello世界"
             fmt.Println(str2[5:8]) // "世"
    (5)字符型:可输出中文完整的ascii编码,使用string()可以转换,0到255
         1)byte,使用单引号包括一个字符,相当于uint8
             var a byte = 'a' 
             fmt.Println(a)  // 97,输出ASCII编码值
         
         2)rune,相当于int32,0到65535
             var b rune = '中'
             fmt.Println(b)  // 20013
    (6) \转义字符
         \n   换行符号
         \t   横向制表符号(多空格)
         \b   回退符号
         \f   换页符号
    (7)零值:一个类型的空值或者说默认值更为准确。
         var i int  // 默认为0
         var s8 string  // 默认为""
         var b3 bool  // 默认为false
2.各种引用数据类型
     1.数组
         1.数组初始化
         (1)初始化一个长度为5的整型数组
             var nums [5]int
     
             names = [3]string{"1","2","3"}
     
             for i := 0; i < index; i++ {
                     newArr[i] = arr[i]
                 }
         (2)也可以用元素初始化
             nums := [5]int{1, 2, 3}
         (3)自动设置长度
             nums := [...]int{3, 8, 7, 12}
     
         (1)下标访问:names[i]
         (2)切片访问:names[n:m],不包括m,从0开始的话,可以省略
             names[:m],names[0:],names[:]
         (3)数组长度:len(数组)
         (4)遍历数组,for循环的简化版
             for key, value := range names {
                 fmt.Println(key, value)
             }
         (5)反转数组:
             func reverseArray(arr [6]int) [6]int {
                 length := len(arr)
                 for i := 0; i < length/2; i++ {
                     arr[i], arr[length-i-1] = arr[length-i-1], arr[i]
                 }
                 return arr
             }
             
             func main() {
                 arr := [6]int{10, 20, 30, 40, 50, 60}
                 reversed := reverseArray(arr)
                 fmt.Println("反转后的数组:", reversed)
             }
         2.二维数组
             1)// 初始化一个 2 行 3 列的二维数组
                 var arr [2][3]int = [2][3]int{  #本质操作行和列
                     {1, 2, 3},
                     {4, 5, 6},
                 }
         
             2)// 使用 ... 自动推断行数
                 arr := [...][3]int{
                     {1, 2, 3},
                     {4, 5, 6},
                 }
                 fmt.Println(arr)
            3) //遍历二维数组,相加列
                 func main() {
                     // 定义命令行参数
                     arr :=[2][2]int{
                         {1,2},
                         {4,3},
                     }
                     res :=make([]int,len(arr[0]))
                     for k,_ :=range arr[0]{ //列
                         sum :=0
                         for k1,_ :=range arr{ //行
                             fmt.Println(arr[k1][k])
                             sum = sum+arr[k1][k]
                         }
                         res[k] = sum
                     }
                     fmt.Println(res)    
                 }
    2.切片:和数组相比就是没有设置长度
         (1)切片的初始化:和数组相比就是没有设置长度
             s := []int{1, 2, 3, 4, 5} // 创建一个包含5个元素的切片
             s := make([]int, 5, 10) // 创建类型为[]int,长度为5,最大容量为10的切片
             
         (2)切片的长度和容量
             len(slice),cap(slice)   //容量第一次成倍扩容,后面一个一个扩容
     
         (3)子切片
             slice[startIndex:endIndex] //子切片的内容改变,父切片的内容也会改变
     
         (4)切片增加元素
             s = []int{1, 2, 3, 4,  5}
             s = append(s, 6, 7, 8) // 向切片中添加元素,返回新的切片
     
         (5)元素展开 
             s1 :=sp[:2]
              s2 :=sp[3:]
              s := append(s1,s2...)  //s2...元素展开,在append函数使用
              fmt.Println(s)
         
         (6)复制拷贝切片
             当需要一个独立副本时,可以使用内置的copy函数来实现
             num1 :=[]int{1,2,3}
             num2 :=make([]int,len(num1))
             copy(目标切片, 源切片)
         
         (7)字节切片:[]byte,字符串每个字符取出是字节,占用 1 个字节的内存空间。
                 
         8)字符串-->转字符切片
                     var str string
             runes :=[]rune(s)
          字符切片(ascci)-->转字符串,占用 4 个字节的内存空间
             string(runes)
    3.指针类型,指向一个内存地址
         (1)指针的申明
             var p *int //指针类型,p表示地址
             *p         //*取值
              p = &a    //&取地址
         
         (2)new函数:分配一个内存
             p :=new(int)
             *p =100
     
     
     4.映射(map)类型:关联键和值的数据结构(无序),查找灵活
     
         (1)可扩展make初始化
             s :=make(map[string]int) //map[键类型][值类型]
             赋值:s["1"]=1
          --
             s :=map[string] int{
                 "key":   value,
                     "Bob":   50000,
                     "Charlie": 60000,    
                 }
         (2)访问值,通过键得到值
             v :=s[key]
         
         (3)删除元素
             delete(映射名字(变量值),“键”)
     
         (4)循环输出
             for key,value :=range 映射的变量名字{
                 fmt.Println(key,value)
             }
             
     5.结构体类型(struct)
         (1)语法结构,定义在main之外
             type 结构体名 struct {
                 字段名1 类型1
                 字段名2 类型2
                 ...
             }
             type Person struct { //首字母大写,导包使用
                 Name string
                 Age  int
                 City string
             }
     
         (2)初始化结构体
             var p Person
             p.Name = "Alice"
             p.Age = 30
             p.City = "Beijing"
           --简化初始化
             s := Person{
                 Name: "Bob",
                 Age: 25, 
                      City: "Shanghai"
                  }
     
             s := Person{
                 "Bob",
                         25,
                         "Shanghai"
              }
         
         (4)匿名结构体
             person := struct {
                 Name string
                 Age  int
             }{
                 Name: "Charlie",
                 Age:  28,
             }
         
         (5)切片和map在结构体中的初始化
                 p2.A_name=[]string{"aa","bb"}
                 p2.Ck=map[string]int{"name":1}
     
     6.Json类型:是一种轻量级的数据交换格式
         {
             "name": "Alice",
             "age": 20,
             "is_married": false,
             "like": ["red", "blue", "purple"],
             "phone": null
         }
         
     
         (1)序列化:json.Marshal,go中的数据转为json格式,序列化。json格式转为go中的数据格式,反序列化    
         设置标签:结构体的标签对应JSON对象的键,也可以不设置使用默认的
             type Person struct {
                 Name    string            `json:"name"`
                 Age     int               `json:"age"`
                 Like    []string          `json:"like"`
                 Address map[string]string `json:"address"`
             }
             // 序列化
             jsonData, err := json.Marshal(p1)
             
             if err != nil {
                 fmt.Println(err)
             }
     
     
         (2)反序列化:json.Unmarshal,将JSON格式的字节切片解码为Go语言结构体。
             // 反序列化
             var p2 Person
             err2 := json.Unmarshal(jsonData, &p2)
             if err != nil {
                 fmt.Println(err2)
             }
             fmt.Println(p2)
 找各种包:studygolang--->标准库中文版,
 八.字符串操作
     (1)遍历:英文,汉字可能会出现乱码,因为一个汉字可能占多个字节。
         str := "Hello"
         for i := 0; i < len(str); i++ {
             fmt.Printf("%c ", str[i])
         }
         fmt.Println()
         
         按字符(rune)遍历
         优点: 能正确处理 UTF-8 编码的多字节字符,避免乱码。
         str := "Hello, 世界"
         for _, char := range str {  //range 遍历数据类型,大多都返回key,value
             fmt.Printf("%c ", char) 
         }
     
     (2)Contains/Index查找字符串
         1)strings.Contains(“源字符串”, “目标字符串”) bool: 判断字符串 s 是否包含子串 substr。
             text := "I love programming in Go!"
             fmt.Println(strings.Contains(text, "Go")) // 输出 true
        2)strings.Index(“源字符串”, “目标字符串”) int: 返回子串 substr 在 s 中首次出现的索引。
             text := "hello, world"
             index := strings.Index(text, "world")
             fmt.Println(index) // 输出 7
    (3)Replace替换字符串
         strings.Replace(“源字符串”, old, new,替换次数) //将 s 中的前 n 个 old 子串替换为 new 子串。
    (4)Split分割字符串:输出为切片
         strings.Split(“源字符串”,"分隔符") //以“分隔符”将 s 分割成多个子串。
    (5)切片-->字符串:Join
         strings.Join(“源字符串切片”, “连接符号”) //将字符串切片 a 中的元素用 sep 连接起来。
    (6)大小写转换
         strings.ToLower(“字符串”)  // 将 s 中的所有字母转换为小写。
         strings.ToUpper(“字符串”)  //将 s 中的所有字母转换为大写。
         strings.TrimSpace(“字符串”) //去除 s 首尾的空格。
九.数据类型转换
     整型和浮点的转换:
         var a int8 = 6
         int16/float64(a) 
         
     字符串转换:
         1)fmt.Sprintf("%d", a):其它类型转字符串,只格式化,不输出
             var a int = 20
             var stra string   //转换的类型
             stra = fmt.Sprintf("%d", a) //格式化输出转换
             fmt.Printf("stra type is %T, value is %v \n", stra, stra)
         
         2)fmt.Sprintf: //不同类型的数据拼接
             var str string = "aa"
             var f1 float32 = 12.2
             var b1 bool = true
             a := fmt.Sprintf("商品标题:%s 价格:%f 是否在售:%t\n",str,f1,b1)
             fmt.Printf(a)
        3)strconv:实现基本数据类型和字符串之间的转换
             字符串和整型相互转换
                 strconv.Atoi(str) #字符串转整型
                 strconv.Itoa(int) #整型转字符串
             字符串和浮点形转换    
                 strconv.ParseFloat(str,64) #字符串转浮点
                 strconv,FormatFloat(num,'f',2,64) #浮点转字符串(要转换的浮点型,输出浮点形,保留2位,64位的)
            字符串和布尔转换
                 strconv.ParseBool(str)  #字符串转布尔
                 strconv.FormatBool(b)   #布尔转字符串
        4)字符串-->转字符切片
                     var str string
             runes :=[]rune(s)
           字符切片(ascci)-->转字符串
             string(runes)
         
         5)strings.Join:"字符串"切片-->转字符串
               result := strings.Join(strSlice, ",")
        
 练习:
 // 创建一个映射,键为学生的姓名(字符串类型),值为一个自定义的 Student 结构体,
 // 该结构体包含 Age(整数类型)和 Scores(整数切片类型,存储学生的多门课程成绩)两个字段。
 // 实现以下功能:
 // - 向映射中添加至少 3 个学生的信息。
 // - 计算并输出每个学生的平均成绩。
 // - 找出平均成绩最高的学生,并输出其姓名和平均成绩。
type Student struct{
     Age int
     Scores []int
 }
 func main() {
     smap :=make(map[string]Student)
     smap["name1"] =Student{
         Age:11,
         Scores: []int{1,3},
     }
     smap["name2"] =Student{
         Age:22,
         Scores: []int{2,4},
     }
     smap["name3"] =Student{
         Age:33,
         Scores: []int{4,6},
     }
     // avg :=make([]int,0)
     // fmt.Println(smap)
     hs :=""
     hc :=0
     for k,_ :=range smap{
         sum :=0
         for _,v1 :=range smap[k].Scores{
             sum =sum+v1    
         }
         // avg =append(avg,sum/len(smap[k].Scores))
         fmt.Printf("%s,%d\n",k,sum/len(smap[k].Scores))
         if hc < sum/len(smap[k].Scores){
             hc = sum/len(smap[k].Scores)
             hs = k
         }
     }
     fmt.Println(hs,hc)
 }        
            
  
