指针和MAP类型

声明指针

指针也是一种数据类型,也可以使用var来声明:var 变量名 *数据类型注意,这里的变量名实际保存的数据是一个十六进制的内存地址,这里的数据类型指的是这个十六进制的内存地址要保存的数据类型。这里就生成了一个int类型的指针。

func main() {
    var a *int//声明变量'a'为'int'类型指针
    *a = 100//根据'*a'的地址赋值
    fmt.Println(a)//输出'*a'的数据
}

运行报错如下:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x64160555b4]
goroutine 1 [running]:
main.main()
/data/data/com.termux/files/home/go/src/socold.com/socold/zhizhen/main.go:8 +0x1c
exit status 2

上面代码为什么会报错?因为只声明了指针a,但是没有初始化。a是一个int类型的指针,应该保存一个十六进制的内存地址,而a保存的这个十六进制的内存地址上应该保存一个int类型的数据。现在的情况是变量a声明了,是一个*int的指针,但是没有初始话,也就是说a啥地址也没保存,你就让我根据地址赋值,但是你还没给我地址呢。所以报错。
注释掉*a = 100可发现输出nil。可以使用内置函数new(int)来为a申请一个内存地址。

func main() {
    var a *int
    a = new(int)
    *a = 100
    fmt.Println(a)
    fmt.Println(*a)
}

指针初始化

aa = new(int)这里需要注意int要跟声明指针时的数据类型一致。初始化后就可以赋值使用了。
一般这种写法很少用,一般都用var a = new (int)写法。new()返回的是一个十六进制的内存地址。这里需要和make()函数区分开,make()也是分配内存的函数,一般用了给slice,map,channel分配内存。make()返回的是数据本身。如下代码:

func main() {
    fmt.Println(make([]int, 1))
    fmt.Println(new(int))
}

指针

指针只要记住两个符号&*就好。&a返回a的内存地址。*b返回的是值,首先b得是一个指针型变量,*b根据指针型变量b保存的地址,取得该地址对应的数据。

a := 19
b := &a
fmt.Printf("a数据类型:%T 值:%v \n", a, a)
fmt.Printf("b数据类型:%T 值:%v \n", b, b)
fmt.Println("-------------------")
fmt.Printf("a地址:%v a值:%v \n", &a, a)
fmt.Printf("b地址:%v b值:%v \n", &b, b)
fmt.Printf("*b值:%v \n", *b)

map类型

map声明

map类型使用var map[key类型]键值类型来声明,map是引用类型,需要使用make(map[string]int,10)来初始化分配内存空间。没有初始化的map类型数据编译时不会报错,运行时会报如下错误:

var ma map[string]int
// ma = make(map[string]int,10)
ma["aa"] = 8
ma["bb"] = 9
ma["cc"] = 10
ma["dd"] = 11
ma["ee"] = 12
fmt.Printf("ma: \n%v", ma)

上面代码报错如下:

panic: assignment to entry in nil map
goroutine 1 [running]:
main.main()
/data/data/com.termux/files/home/go/src/socold.com/socold/zhizhen/main.go:55 +0x3c
exit status 2
[Done] exited with code=1 in 1.402271 seconds

初始化map

初始化map是建议预先估算好map的容量,虽然map可以动态扩容,但是会影响程序运行效率。初始化map的语句ma = make(map[key类型]键值类型,map容量)
如何使用map类型数据:ma["aa"]即可返回键为"aa"的值8。如果键不存在会返回键值对应数据类型的0值。一般用if语句来判断key存不存在。如下代码:

v, ok := ma["zz"]
if !ok {
    fmt.Println("key:ma['zz']不存在。")
} else {
    fmt.Printf("ma: %v \n", v)
}

遍历map

map类型数据的遍历和数组一样用for k,v := range ma{}语句。map类型遍历出来是随机的,无序的。有可能keyma["aa"]排第一个也有可能排最后一个。

func main() {
    var ma map[string]int
    ma = make(map[string]int, 10)
    ma["aa"] = 8
    ma["bb"] = 9
    ma["cc"] = 10
    ma["dd"] = 11
    ma["ee"] = 12
    for k, v := range ma {
        fmt.Printf("key:%v value:%v \n", k, v)
    }
}

删除map元素

删除map元素需要用delete(ma,"aa")。如果要删除的key不存在,程序不会进行任何操作。

func main() {
    var ma map[string]int
    ma = make(map[string]int, 10)
    ma["aa"] = 8
    ma["bb"] = 9
    ma["cc"] = 10
    ma["dd"] = 11
    ma["ee"] = 12
    for k, v := range ma {
        fmt.Printf("key:%v value:%v \n", k, v)
    }

    //删除map类型变量ma中的元素
    delete(ma, "aa")

    fmt.Println("-----------------------------")
    for k, v := range ma {
        fmt.Printf("key:%v value:%v \n", k, v)
    }
}

map变种

值为切片的map
func main() {
    var ma map[string][]int
    ma = make(map[string][]int, 3)
    aa := []int{0, 9, 8}
    bb := []int{1, 2, 3, 4, 5}
    cc := []int{6, 7}
    ma["切片1"] = aa
    ma["切片2"] = bb
    ma["切片2"] = cc
    fmt.Printf("值为切片的map:\n %v \n", ma)
}

其实吧,这样写没啥问题,但是有点麻烦,看下面这个写法,更简单:

ma["切片1"] = []int{8, 3, 6}
ma["切片2"] = []int{4, 5, 0, 1, 6}
fmt.Printf("%v", ma)
值为map的切片
var qie = make([]map[string]int, 2, 3)
qie[0] = make(map[string]int, 2)
qie[0]["铁锤"] = 18
qie[0]["二牛"] = 14
fmt.Println(qie)

报错提示

某些错误写法的报错提示:

  1. 索引越界。下面代码编译是没问题,运行出错。愿因是切片qie声明并初始化时make()函数内只给了容量为3,元素数量给的是0,给的报错信息是index out of range [0] with length 0,学名叫索引越界。
    var qie = make([]map[string]int, 0, 3)
    qie[0]["切片1"] = 9
    fmt.Println(qie)
    索引越界错误提示。

    panic: runtime error: index out of range [0] with length 0
    goroutine 1 [running]:
    main.main()
    /data/data/com.termux/files/home/go/src/socold.com/socold/zhizhen/main.go:155 +0x3c
    exit status 2
    [Done] exited with code=1 in 1.514425 seconds

  1. map没有初始化编译器不会报错,运行时报如下错误,报错提示信息为assignment to entry in nil map
    var qie = make([]map[string]int, 1, 3)
    qie[0]["切片1"] = 9
    fmt.Println(qie)
    错误提示信息:

    panic: assignment to entry in nil map
    goroutine 1 [running]:
    main.main()
    /data/data/com.termux/files/home/go/src/socold.com/socold/zhizhen/main.go:168 +0x68
    exit status 2
    [Done] exited with code=1 in 1.443653 seconds

实例代码

识别字符串中的中文

研究下这个代码,这是一个识别给定字符串中有几个中文的代码。需要引入unicode包。

func main() {
    i := 0
    s := "abcd今天不太冷あなたは日本人ですこんにちは안녕하세요"
    for _, v := range s {
        if unicode.Is(unicode.Han, v) {  //unicode.Hangul是韩文,unicode.Hiragana是平假名,应该是日文。
            i++
        }
    }
    fmt.Println(i)
}

回文判断

来一个实例,判断给定的字符串是不是回文:

func huiwen(s string) bool {
    //建一个切片
    s1 := make([]string, 0, len(s))
    //把字符串导入切片s1
    for _, v := range s {
        s1 = append(s1, string(v))
    }
    //遍历切片s1
    for i := 0; i < len(s1)/2; i++ {
        if s1[i] != s1[len(s1)-1-i] {
            return false
        }
    }
    return true
}
func main() {
    //回文判断:
    s := "上海自来水来自海上a"
    if huiwen(s) {
        fmt.Println("是回文")
    } else {
        fmt.Println("不是回文")
    }

}

计算单词出现次数

在来一个实例。给一段英文短文,要求计算每个单词出现的次数,不能区分大小写。

func main() {
    //返回给定字符串中个单词出现的次数。
    s := "An old woman had a cat. The cat was very old; she could not run quickly, and she could not bite, because she was so old. One day the old cat saw a mouse;"

    //预处理字符串
    var s1 []string
    var word string
    for _, v := range s {

        if unicode.IsLetter(v) {
            //如果是字母,保存到字符串缓存
            word += string(unicode.ToLower(v))
        } else if word != "" {
            //如果不是字母,
            s1 = append(s1, word)
            word = ""
        }
    }

    //将处理好的缓存切片's1'导入'map'并计算单词出现次数。
    //声明并初始化一个map
    smap := make(map[string]int, 30)
    //切片s1导入map并计算单词出现的次数
    for _, v := range s1 {
        if _, k := smap[v]; k {
            smap[v]++
        } else {
            smap[v] = 1
        }
    }

    //遍历smap
    for v, k := range smap {
        fmt.Printf("smap[%v]-[%v] \n", k, v)
    }
}

  转载请注明: So Cold 指针和MAP类型

 上一篇
自定义类型 类型别名 结构体和json 自定义类型 类型别名 结构体和json
类型别名和自定义类型在Go语言中有一些基本的数据类型,如string、整型、浮点型、布尔等数据类型, Go语言中可以使用type关键字来定义自定义类型。自定义类型是定义了一个全新的类型。我们可以基于内置的基本类型定义,也可以通过struct
2020-04-22
下一篇 
Go语言数据类型 Go语言数据类型
数据类型整数主要分两类int和uint。 int类型有符号整数型。 int类型编译器自动推导默认的类型。你的程序在32位操作系统下运行就是int32,你的程序在64位操作系统下运行就是int64。所以在使用int类型时不建议指定int32
2020-03-06
  目录