值类型与引用类型
- 值类型:int系列、float系列、bool、string 、数组、结构体struct
- 引用类型:指针、slice切片、map、管道chan, interface,作为参数时,传递的是标头值
引用类型与指针
- 变量在定义时,前面有用标识,那么就是引用类型,如:int。或自带的类型,slice,map,chan等
- 变量存的是一个指针(内存地址),那就是引用类型
int系列
float系列
其他数字类型

var a byte= 'a'b:=1fmt.Printf("%c",a+byte(b)) //'b'
数值型的转换
var i int32 = 10var n int64 =20//数据类型转换fmt.Println(int64(i)+n)var m float32 = 20.3//数据类型转换fmt.Println(float32(i)+m)
布尔型
- true
-
字符串
string,须使用双引号进行赋值操作
-
遍历
func main(){var str string = "hello哈哈"//遍历汉字,一个中文汉字占3个字节,所有用普通的for len遍历会乱码str2 := []rune(str)//将字符串转为切片后再进行遍历//将切片转为字符串,str3=string(str2)//为什么不用str2 := []byte(str),因为一个汉字的=3个字节,而byte类型只有1个字节,而有4个字节for i:=0;i<len(str2);i++{fmt.Printf("%c\n",str2[i])}//或者通过for range来遍历for i ,v :=range str{fmt.Printf("index=%v,value=%c\n",i,v)}}
字符串转数值
func main(){var s1 string = "a123"var s2 string = "true"var s3 string = "100"var s4 string = "100.123"var result int64result,_ = strconv.ParseInt(s1,10,64)fmt.Printf("类型:%T,值:%v\n",result,result) //转型错误,结果为0result,_ = strconv.ParseInt(s3,10,64)fmt.Printf("类型:%T,值:%v\n",result,result)var result1 boolresult1,_ = strconv.ParseBool(s2)fmt.Printf("类型:%T,值:%v\n",result1,result1)var result2 float64result2,_ = strconv.ParseFloat(s4,64)fmt.Printf("类型:%T,值:%v\n",result2,result2)}
数值转字符串
func main(){num1 :=99var num2 float64 = 12.345b :=truevar char byte ='a'var str stringstr= fmt.Sprintf("%d",num1)fmt.Printf("str :type=%T , value=%q\n",str,str)str= fmt.Sprintf("%f",num2)fmt.Printf("str :type=%T , value=%q\n",str,str)str= fmt.Sprintf("%t",b)fmt.Printf("str :type=%T , value=%q\n",str,str)str= fmt.Sprintf("%c",char)fmt.Printf("str :type=%T , value=%q\n",str,str)// 通过strconv进行转换num3 :=99var num4 float64 = 12.345b2 :=truestr=strconv.FormatInt(int64(num3),10)fmt.Printf("str :type=%T , value=%q\n",str,str)str=strconv.FormatFloat(num4,'f',10,64)fmt.Printf("str :type=%T , value=%q\n",str,str)str=strconv.FormatBool(b2)fmt.Printf("str :type=%T , value=%q\n",str,str)}
数组
定义
func main() {//方式一:var array0 [3] intfmt.Println(array0) //[0 0 0]array0[0]=1array0[1]=2array0[2]=3fmt.Println(array0) //[1 2 3]//方式二:var array1 [3]int = [3]int{1,2,3}fmt.Println(array1) //[1 2 3]//方式三:var array2 = [3]int{1,2,3}fmt.Println(array2) //[1 2 3]//方式四:var array3 = [...]int{1,2,3}fmt.Println(array3) //[1 2 3]//方式五:var array4 = [...]int{0:1,1:3,2:2}fmt.Println(array4) //[1 3 2]//方式六://不定长度的数组的长度由元素来决定array5 :=[...]string{0:"tom",2:"jack",3:"mary"}fmt.Println(array5,len(array5)) //[tom jack mary] 4}//二维数组:var array [2][3] int//3行4列var array [...][3] int//注意后面的长度不能省略array :=[...][3]int{{1,2,3},{4,5,6}}array[0][1]=2更高维度:var array [len][len]...[len] int
遍历
func main() {array :=[...]string{0:"tom",2:"jack",3:"mary"}for i:=0;i<len(array);i++{fmt.Printf("index=%v,value=%q\n",i,array[i])}fmt.Println("----------------分割线-----------------")//用for range遍历for k,v :=range array{fmt.Printf("index=%v,value=%q\n",k,v)}}
切片
定义
func main() {var slice []int//这样定义,使用前要先makeslice = make([]int,0,10)//方式一:定义数组后,通过引用数组来实现var arr =[...]int{1,2,3,4,5}//切片是对数组的引用,可以看为是一个动态的数组slice :=arr[1:4]//含头不含尾fmt.Println("arr数组的元素是",arr) //[1 2 3 4 5]fmt.Println("slice切片的元素是",slice) //slice切片的元素是 [2 3 4]fmt.Println("slice切片的长度是",len(slice)) //slice切片的长度是 3fmt.Println("slice切片的容量是",cap(slice))//slice切片的容量是 4 ..切片的容量>=长度,//容量与长度为什么不相等,slice :=arr[1:4],注意容量是按:前的下标开始算,到最后一个元素的。//方式二:var slice2 []int =make([]int,10,15)//参数:type,len,cap,cap可以不指定//方式三:通过这种方式创建,len与cap相等var slice3 []string = []string{"a","b","c"}//方式四slice4 :=new([]string)}
遍历:与数组一致
注意事项
- arr[:]—-数组全部
- arr[1:]—-除了index=0不要
- arr[:3]—-前3个元素
append
func main() {var arr =[...]int{1,2,3,4,5}//切片是对数组的引用,可以看为是一个动态的数组slice1 :=arr[1:4]//含头不含尾var slice2 []int =[]int{6,7,8}slice1=append(slice1,slice2...)fmt.Println(slice1)}
copy
func main() {slice1 := make([]int,10)var slice2 []int =[]int{1,2,3,4,5}copy(slice1,slice2)//将slice2拷贝给slice1,按位替换,不会追加,slice1的长度不会改变fmt.Println(slice1)//[1 2 3 4 5 0 0 0 0 0]}//copy是值拷贝
截取
注意:截取是按容量截取的 ```go package mainfunc main() {arr :=[...]int{1,2,3,4,5}slice :=arr[:]fmt.Println(slice)//[1 2 3 4 5]//切片的截取newslice :=append(slice[0:2],slice[3:]...)arr[0]=0//注意newslice任然是对arr的引用fmt.Println(newslice)//[0 2 4 5]newslice[0]=6//切片是对数组的引用,改切片内元素(指针)的值会将原数组也改掉fmt.Println(arr) //[6 2 3 4 5]}
import “fmt” func main() { a := make([]int,10,100) a1 := a[9:12] fmt.Println(a1) //[0 0 0] fmt.Println(len(a1)) //3 fmt.Println(cap(a1)) //91 b := make([]int,10) fmt.Println(b[9:12]) //panic: runtime error: slice bounds out of range [:12] with capacity 10 }
<a name="gCLvj"></a>#### 截取指定容量```gofunc main() {a := make([]int,10,100)a1 := a[9:12:12]fmt.Println(a1) //[0 0 0]fmt.Println(len(a1)) //3fmt.Println(cap(a1)) //3a1[0] = 100fmt.Println(a) // [0 0 0 0 0 0 0 0 0 100]}
map
定义
func main() {**如果先定义var map1 map[int]string,那么使用时,一定要先make方式一://定义mapvar map1 map[int]string//其中int为key的类型,string为value的类型//在使用map前要先make,make的作用是为map分配空间map1=make(map[int]string,10)//type,size。在生成map时,size可以不用指定,会自动扩充map1[0]="a"map1[1]="b"fmt.Println(map1)//map[0:a 1:b]方式二:map2 :=make(map[int]string)map2[0]="c"map2[1]="d"fmt.Println(map2)//map[0:c 1:d]方式三:map3 :=map[int]string{0:"e",1:"f",}fmt.Println(map3)//map[0:e 1:f]}这种方式类似上面的方式三type MyDict map[string]stringfunc main() {my := MyDict{"a":"1","b":"2"}fmt.Println(my)}func main() {my := MyDict{}my["a"]="1"my["b"]="2"}
//map的value为数组,注意数组的长度要固定,否则use of [...] array outside of array literalHeader := map[string][1]string{"Accept-Encoding": {"gzip, deflate"},"Accept-Language": {"en-us"},"Connection": {"keep-alive"},}//map的value为切片Header := map[string][]string{"Accept-Encoding": {"gzip, deflate"},"Accept-Language": {"en-us"},"Connection": {"keep-alive"},}//map的value再定义为mapmap4 :=make(map[string]map[string]string)map4["tom"]=make(map[string]string)map4["tom"]["sex"]="男"fmt.Println(map4)//map[tom:map[sex:男]]
CUDR
增与改:map1[0]="a"查:val,ok := map1[0],ok为true(查询成功)或false(查询失败,val为零值,及map中没有该key)查:val := map1[0],查询失败,val为零值删:delete(map1,0),如果没有,不会报错全删:map1 :=make(map[int]string),make一个新空间
遍历
func main() {map1:=make(map[int]string,10)//type,size。在生成map时,size可以不用指定,会自动扩充map1[0]="a"map1[1]="b"map1[3]="c"for k,v :=range map1{fmt.Printf("key:%v,value:%v\n",k,v)}for k:=range map1{ // 这样只遍历map1的所有keyfmt.Printf("key:%v\n",k)}}key:0,value:akey:1,value:bkey:3,value:c
func main() {map4 :=make(map[string]map[string]string)map4["tom"]=make(map[string]string)map4["tom"]["sex"]="男"map4["tom"]["age"]="20"map4["mary"]=make(map[string]string)map4["mary"]["sex"]="女"map4["mary"]["age"]="18"for k,v :=range map4{fmt.Printf("第一层key为%v\n",k)for i,m :=range v{fmt.Printf("key:%v,value:%v\n",i,m)}}}第一层key为tomkey:age,value:20key:sex,value:男第一层key为marykey:sex,value:女key:age,value:18
map切片
func main() {//声明map切片student :=make([]map[string]string,1)student[0]= make(map[string]string)student[0]["name"]="tom"student[0]["sex"]="男"newstudent := make(map[string]string)newstudent["name"]="mary"newstudent["sex"]="女"student = append(student,newstudent)fmt.Println(student)//[map[name:tom sex:男] map[name:mary sex:女]]}
深拷贝
最简单的方法是用json unmarshal,变成字符串,然后再用 json marshal生成新的map。这种方法对结构体也适用。
如果是map[string]interface{}和[]interface{}的组合,用代码递归也很简单:
func DeepCopy(value interface{}) interface{} {if valueMap, ok := value.(map[string]interface{}); ok {newMap := make(map[string]interface{})for k, v := range valueMap {newMap[k] = DeepCopy(v)}return newMap} else if valueSlice, ok := value.([]interface{}); ok {newSlice := make([]interface{}, len(valueSlice))for k, v := range valueSlice {newSlice[k] = DeepCopy(v)}return newSlice}return value}
零值
var b bool // falsevar s string // ""var f float系列 //0var i int系列 //0var a [2]int //[0 0],由于数组在定义时必须制定长度,所以它的零值为[0 0 ...]// 以下六种类型零值常量都是nilvar a *intvar a []int,注意这个是切片不是数组var a map[string] intvar a chan intvar a func(string) intvar a error // error是接口
