值类型与引用类型

  • 值类型:int系列、float系列、bool、string 、数组、结构体struct
  • 引用类型:指针、slice切片、map、管道chan, interface,作为参数时,传递的是标头值

_

引用类型与指针

  • 变量在定义时,前面有用标识,那么就是引用类型,如:int。或自带的类型,slice,map,chan等
  • 变量存的是一个指针(内存地址),那就是引用类型

_

int系列

image.png

float系列

image.png

其他数字类型

image.png

  1. var a byte= 'a'
  2. b:=1
  3. fmt.Printf("%c",a+byte(b)) //'b'

数值型的转换

  1. var i int32 = 10
  2. var n int64 =20
  3. //数据类型转换
  4. fmt.Println(int64(i)+n)
  5. var m float32 = 20.3
  6. //数据类型转换
  7. fmt.Println(float32(i)+m)

布尔型

  • true
  • false

    字符串

  • string,须使用双引号进行赋值操作

  • 字符串的本质是[]byte

    遍历

    1. func main(){
    2. var str string = "hello哈哈"
    3. //遍历汉字,一个中文汉字占3个字节,所有用普通的for len遍历会乱码
    4. str2 := []rune(str)//将字符串转为切片后再进行遍历
    5. //将切片转为字符串,str3=string(str2)
    6. //为什么不用str2 := []byte(str),因为一个汉字的=3个字节,而byte类型只有1个字节,而有4个字节
    7. for i:=0;i<len(str2);i++{
    8. fmt.Printf("%c\n",str2[i])
    9. }
    10. //或者通过for range来遍历
    11. for i ,v :=range str{
    12. fmt.Printf("index=%v,value=%c\n",i,v)
    13. }
    14. }

    字符串转数值

    1. func main(){
    2. var s1 string = "a123"
    3. var s2 string = "true"
    4. var s3 string = "100"
    5. var s4 string = "100.123"
    6. var result int64
    7. result,_ = strconv.ParseInt(s1,10,64)
    8. fmt.Printf("类型:%T,值:%v\n",result,result) //转型错误,结果为0
    9. result,_ = strconv.ParseInt(s3,10,64)
    10. fmt.Printf("类型:%T,值:%v\n",result,result)
    11. var result1 bool
    12. result1,_ = strconv.ParseBool(s2)
    13. fmt.Printf("类型:%T,值:%v\n",result1,result1)
    14. var result2 float64
    15. result2,_ = strconv.ParseFloat(s4,64)
    16. fmt.Printf("类型:%T,值:%v\n",result2,result2)
    17. }

    数值转字符串

    1. func main(){
    2. num1 :=99
    3. var num2 float64 = 12.345
    4. b :=true
    5. var char byte ='a'
    6. var str string
    7. str= fmt.Sprintf("%d",num1)
    8. fmt.Printf("str :type=%T , value=%q\n",str,str)
    9. str= fmt.Sprintf("%f",num2)
    10. fmt.Printf("str :type=%T , value=%q\n",str,str)
    11. str= fmt.Sprintf("%t",b)
    12. fmt.Printf("str :type=%T , value=%q\n",str,str)
    13. str= fmt.Sprintf("%c",char)
    14. fmt.Printf("str :type=%T , value=%q\n",str,str)
    15. // 通过strconv进行转换
    16. num3 :=99
    17. var num4 float64 = 12.345
    18. b2 :=true
    19. str=strconv.FormatInt(int64(num3),10)
    20. fmt.Printf("str :type=%T , value=%q\n",str,str)
    21. str=strconv.FormatFloat(num4,'f',10,64)
    22. fmt.Printf("str :type=%T , value=%q\n",str,str)
    23. str=strconv.FormatBool(b2)
    24. fmt.Printf("str :type=%T , value=%q\n",str,str)
    25. }

    数组

    定义

    1. func main() {
    2. //方式一:
    3. var array0 [3] int
    4. fmt.Println(array0) //[0 0 0]
    5. array0[0]=1
    6. array0[1]=2
    7. array0[2]=3
    8. fmt.Println(array0) //[1 2 3]
    9. //方式二:
    10. var array1 [3]int = [3]int{1,2,3}
    11. fmt.Println(array1) //[1 2 3]
    12. //方式三:
    13. var array2 = [3]int{1,2,3}
    14. fmt.Println(array2) //[1 2 3]
    15. //方式四:
    16. var array3 = [...]int{1,2,3}
    17. fmt.Println(array3) //[1 2 3]
    18. //方式五:
    19. var array4 = [...]int{0:1,1:3,2:2}
    20. fmt.Println(array4) //[1 3 2]
    21. //方式六:
    22. //不定长度的数组的长度由元素来决定
    23. array5 :=[...]string{0:"tom",2:"jack",3:"mary"}
    24. fmt.Println(array5,len(array5)) //[tom jack mary] 4
    25. }
    26. //二维数组:
    27. var array [2][3] int//3行4列
    28. var array [...][3] int//注意后面的长度不能省略
    29. array :=[...][3]int{{1,2,3},{4,5,6}}
    30. array[0][1]=2
    31. 更高维度:
    32. var array [len][len]...[len] int

    遍历

    1. func main() {
    2. array :=[...]string{0:"tom",2:"jack",3:"mary"}
    3. for i:=0;i<len(array);i++{
    4. fmt.Printf("index=%v,value=%q\n",i,array[i])
    5. }
    6. fmt.Println("----------------分割线-----------------")
    7. //用for range遍历
    8. for k,v :=range array{
    9. fmt.Printf("index=%v,value=%q\n",k,v)
    10. }
    11. }

切片

定义

  1. func main() {
  2. var slice []int//这样定义,使用前要先make
  3. slice = make([]int,0,10)
  4. //方式一:定义数组后,通过引用数组来实现
  5. var arr =[...]int{1,2,3,4,5}
  6. //切片是对数组的引用,可以看为是一个动态的数组
  7. slice :=arr[1:4]//含头不含尾
  8. fmt.Println("arr数组的元素是",arr) //[1 2 3 4 5]
  9. fmt.Println("slice切片的元素是",slice) //slice切片的元素是 [2 3 4]
  10. fmt.Println("slice切片的长度是",len(slice)) //slice切片的长度是 3
  11. fmt.Println("slice切片的容量是",cap(slice))//slice切片的容量是 4 ..切片的容量>=长度,
  12. //容量与长度为什么不相等,slice :=arr[1:4],注意容量是按:前的下标开始算,到最后一个元素的。
  13. //方式二:
  14. var slice2 []int =make([]int,10,15)//参数:type,len,cap,cap可以不指定
  15. //方式三:通过这种方式创建,len与cap相等
  16. var slice3 []string = []string{"a","b","c"}
  17. //方式四
  18. slice4 :=new([]string)
  19. }

遍历:与数组一致

注意事项

  • arr[:]—-数组全部
  • arr[1:]—-除了index=0不要
  • arr[:3]—-前3个元素

    append

    1. func main() {
    2. var arr =[...]int{1,2,3,4,5}
    3. //切片是对数组的引用,可以看为是一个动态的数组
    4. slice1 :=arr[1:4]//含头不含尾
    5. var slice2 []int =[]int{6,7,8}
    6. slice1=append(slice1,slice2...)
    7. fmt.Println(slice1)
    8. }

    copy

    1. func main() {
    2. slice1 := make([]int,10)
    3. var slice2 []int =[]int{1,2,3,4,5}
    4. copy(slice1,slice2)//将slice2拷贝给slice1,按位替换,不会追加,slice1的长度不会改变
    5. fmt.Println(slice1)//[1 2 3 4 5 0 0 0 0 0]
    6. }
    7. //copy是值拷贝

    截取

    1. func main() {
    2. arr :=[...]int{1,2,3,4,5}
    3. slice :=arr[:]
    4. fmt.Println(slice)//[1 2 3 4 5]
    5. //切片的截取
    6. newslice :=append(slice[0:2],slice[3:]...)
    7. arr[0]=0//注意newslice任然是对arr的引用
    8. fmt.Println(newslice)//[0 2 4 5]
    9. newslice[0]=6
    10. //切片是对数组的引用,改切片内元素(指针)的值会将原数组也改掉
    11. fmt.Println(arr) //[6 2 3 4 5]
    12. }
    注意:截取是按容量截取的 ```go package main

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 }

  1. <a name="gCLvj"></a>
  2. #### 截取指定容量
  3. ```go
  4. func main() {
  5. a := make([]int,10,100)
  6. a1 := a[9:12:12]
  7. fmt.Println(a1) //[0 0 0]
  8. fmt.Println(len(a1)) //3
  9. fmt.Println(cap(a1)) //3
  10. a1[0] = 100
  11. fmt.Println(a) // [0 0 0 0 0 0 0 0 0 100]
  12. }

map

定义

  1. func main() {
  2. **如果先定义var map1 map[int]string,那么使用时,一定要先make
  3. 方式一:
  4. //定义map
  5. var map1 map[int]string//其中int为key的类型,string为value的类型
  6. //在使用map前要先make,make的作用是为map分配空间
  7. map1=make(map[int]string,10)//type,size。在生成map时,size可以不用指定,会自动扩充
  8. map1[0]="a"
  9. map1[1]="b"
  10. fmt.Println(map1)//map[0:a 1:b]
  11. 方式二:
  12. map2 :=make(map[int]string)
  13. map2[0]="c"
  14. map2[1]="d"
  15. fmt.Println(map2)//map[0:c 1:d]
  16. 方式三:
  17. map3 :=map[int]string{
  18. 0:"e",
  19. 1:"f",
  20. }
  21. fmt.Println(map3)//map[0:e 1:f]
  22. }
  23. 这种方式类似上面的方式三
  24. type MyDict map[string]string
  25. func main() {
  26. my := MyDict{"a":"1","b":"2"}
  27. fmt.Println(my)
  28. }
  29. func main() {
  30. my := MyDict{}
  31. my["a"]="1"
  32. my["b"]="2"
  33. }
  1. //map的value为数组,注意数组的长度要固定,否则use of [...] array outside of array literal
  2. Header := map[string][1]string{
  3. "Accept-Encoding": {"gzip, deflate"},
  4. "Accept-Language": {"en-us"},
  5. "Connection": {"keep-alive"},
  6. }
  7. //map的value为切片
  8. Header := map[string][]string{
  9. "Accept-Encoding": {"gzip, deflate"},
  10. "Accept-Language": {"en-us"},
  11. "Connection": {"keep-alive"},
  12. }
  13. //map的value再定义为map
  14. map4 :=make(map[string]map[string]string)
  15. map4["tom"]=make(map[string]string)
  16. map4["tom"]["sex"]="男"
  17. fmt.Println(map4)//map[tom:map[sex:男]]

CUDR

  1. 增与改:map1[0]="a"
  2. 查:val,ok := map1[0],oktrue(查询成功)或false(查询失败,val为零值,及map中没有该key)
  3. 查:val := map1[0],查询失败,val为零值
  4. 删:delete(map1,0),如果没有,不会报错
  5. 全删:map1 :=make(map[int]string),make一个新空间

遍历

  1. func main() {
  2. map1:=make(map[int]string,10)//type,size。在生成map时,size可以不用指定,会自动扩充
  3. map1[0]="a"
  4. map1[1]="b"
  5. map1[3]="c"
  6. for k,v :=range map1{
  7. fmt.Printf("key:%v,value:%v\n",k,v)
  8. }
  9. for k:=range map1{ // 这样只遍历map1的所有key
  10. fmt.Printf("key:%v\n",k)
  11. }
  12. }
  13. key:0,value:a
  14. key:1,value:b
  15. key:3,value:c
  1. func main() {
  2. map4 :=make(map[string]map[string]string)
  3. map4["tom"]=make(map[string]string)
  4. map4["tom"]["sex"]="男"
  5. map4["tom"]["age"]="20"
  6. map4["mary"]=make(map[string]string)
  7. map4["mary"]["sex"]="女"
  8. map4["mary"]["age"]="18"
  9. for k,v :=range map4{
  10. fmt.Printf("第一层key为%v\n",k)
  11. for i,m :=range v{
  12. fmt.Printf("key:%v,value:%v\n",i,m)
  13. }
  14. }
  15. }
  16. 第一层keytom
  17. key:age,value:20
  18. key:sex,value:男
  19. 第一层keymary
  20. key:sex,value:女
  21. key:age,value:18

map切片

  1. func main() {
  2. //声明map切片
  3. student :=make([]map[string]string,1)
  4. student[0]= make(map[string]string)
  5. student[0]["name"]="tom"
  6. student[0]["sex"]="男"
  7. newstudent := make(map[string]string)
  8. newstudent["name"]="mary"
  9. newstudent["sex"]="女"
  10. student = append(student,newstudent)
  11. fmt.Println(student)//[map[name:tom sex:男] map[name:mary sex:女]]
  12. }

深拷贝

最简单的方法是用json unmarshal,变成字符串,然后再用 json marshal生成新的map。这种方法对结构体也适用。
如果是map[string]interface{}和[]interface{}的组合,用代码递归也很简单:

  1. func DeepCopy(value interface{}) interface{} {
  2. if valueMap, ok := value.(map[string]interface{}); ok {
  3. newMap := make(map[string]interface{})
  4. for k, v := range valueMap {
  5. newMap[k] = DeepCopy(v)
  6. }
  7. return newMap
  8. } else if valueSlice, ok := value.([]interface{}); ok {
  9. newSlice := make([]interface{}, len(valueSlice))
  10. for k, v := range valueSlice {
  11. newSlice[k] = DeepCopy(v)
  12. }
  13. return newSlice
  14. }
  15. return value
  16. }

零值

  1. var b bool // false
  2. var s string // ""
  3. var f float系列 //0
  4. var i int系列 //0
  5. var a [2]int //[0 0],由于数组在定义时必须制定长度,所以它的零值为[0 0 ...]
  6. // 以下六种类型零值常量都是nil
  7. var a *int
  8. var a []int,注意这个是切片不是数组
  9. var a map[string] int
  10. var a chan int
  11. var a func(string) int
  12. var a error // error是接口