声明指针
指针也是一种数据类型,也可以使用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)报错提示
某些错误写法的报错提示:
- 索引越界。下面代码编译是没问题,运行出错。愿因是切片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
- 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)
    }
} 
                     
                     
                        
                        