• 你不知道的Golang盲点汇总【持续更新】


    1. 引用传递时append会复制生成新的指针

    
    
    package main
    import ( "fmt" ) func w(s []int )[]int{ fmt.Printf("in w %v %#v ",s ,&s[0] )
      //append后s指定新复制的内存指针了,不再指向原来的内存 s
    =append(s, 0) fmt.Printf("after append w %v %#v ",s ,&s[0] ) return s } func main() { s:=[]int{1} fmt.Printf("out of w %v %#v ",s ,&s[0] ) s2:=w(s)
    //原来的指针s的内容依然在内存中,而不是被覆盖/GC了 fmt.Printf(
    "after w %v %#v %v %#v ",s ,&s[0],s2 ,&s2[0] ) }

    output:

    out of w [1] (*int)(0x40e020) in w [1] (*int)(0x40e020) after append w [1 0] (*int)(0x40e040) after w [1] (*int)(0x40e020) [1 0] (*int)(0x40e040)

    2. 空值append

    package main
    
    import (
        "fmt"
    )
    
    func main() {
        s:=[][]int{}
        //使用...更加方便,还不会导致塞入空值
        fmt.Println("Hello, playground", append(s, [][]int{}... ), append(s, []int{} ))
    }

    output:

    Hello, playground [] [[]]
    

    3. 数组、slice、切片的雷!

    package main
    
    import (
        "fmt"
        "reflect"
    )
    
    func main() {
        //固定长度是array类型,可以覆盖成员,但不能修改长度,即不能append 
        a := [4]int{1,2}
        a[0]=9
        //没设置长度是slice类型,即动态或不定长数组, 也能覆盖成员,也修改长度,即支持append
        s := []int{1,2}
        //s[1:len(s):cap(s)] 等效 s[1:len(s)]
        s[0]=9
        //注意下村是:左开(含左边元素),右闭(不含右边元素)
        fmt.Printf("%#v %#v %v %v %#v %#v %#v 
    ", a ,s, reflect.TypeOf(a).Kind(), reflect.TypeOf(s).Kind(), a[1:len(a)], s[1:len(s):cap(s)],s[1:len(s)],  )
        
        //subslice切片
        //切片,也叫subslice,是一块基于父slice的投影
        subArray:=a[0:2]
        //报错:invalid slice index: 3 > 2, 即len不能超过cap
        //subArray2:=subArray[0:3:2]
        subArray2:=subArray[0:1:2]
        //报错:index out of range [1] with length 1
        //subArray2[1]=222
        //报错:index out of range [1] with length 1,len+offset>父slice的cap ,投影不能超出父slice的cap区域
        //subArray3:=subArray2[1:2:2]
        subArray3:=subArray2[0:]
        //切片是指定父slice的指针,所以会修改父slice,使用时一定要小心!!!
        subArray3[0]=222
        
        //subArray虽然是新变量名,但实际指定同一个内存地址
        fmt.Printf("subslice %#v %#v  %#v  %#v  %v %v %v %v
    ", subArray, a, subArray2,subArray3, &subArray[0], &a[0], &subArray2[0],&subArray3[0])
        
        
        //扩容测试
        fmt.Printf("%v %v 
    ", len(s), cap(s))
        s=append(s, 1)
        fmt.Printf("%v %v 
    ", len(s), cap(s))
        s=append(s, 1)
        fmt.Printf("%v %v 
    ", len(s), cap(s))
        //tmp:=[8]int{}
        //错误:cannot use tmp (type [8]int) as type []int in append
        //正确玩法:
        //不能用Printf中有unicode,否则会 format %扩 has unknown verb 扩
        fmt.Println("len增加且超过cap时,若<=1024,以100%扩容 ")
        s=[]int{}
        i:=64
        for i>=0 {
            fmt.Printf("%v %v 
    ", len(s), cap(s)) 
            s=append(s,1)
            i-=1
        }
    
        fmt.Println("len增加且超过cap>1024时,否则以大约25%扩容,注意是大约")
        //大约25%扩容详细参考: https://juejin.im/post/5ca4239ef265da30807fea48
        i=1028
        s=[]int{}
        for i>=0 {
            s=append(s,1)
            i-=1
            if i%100==0{
                fmt.Printf("%v %v 
    ", len(s), cap(s)) 
            }
        }
        
    }

    output:

    [4]int{9, 2, 0, 0} []int{9, 2} array slice []int{2, 0, 0} []int{2} []int{2} 
    subslice []int{222, 2} [4]int{222, 2, 0, 0}  []int{222}  []int{222}  0x40e020 0x40e020 0x40e020 0x40e020
    2 2 
    3 4 
    4 4 
    len增加且超过cap时,若<=1024,以100%扩容 
    0 0 
    1 2 
    2 2 
    3 4 
    4 4 
    5 8 
    6 8 
    7 8 
    8 8 
    9 16 
    10 16 
    11 16 
    12 16 
    13 16 
    14 16 
    15 16 
    16 16 
    17 32 
    18 32 
    19 32 
    20 32 
    21 32 
    22 32 
    23 32 
    24 32 
    25 32 
    26 32 
    27 32 
    28 32 
    29 32 
    30 32 
    31 32 
    32 32 
    33 64 
    34 64 
    35 64 
    36 64 
    37 64 
    38 64 
    39 64 
    40 64 
    41 64 
    42 64 
    43 64 
    44 64 
    45 64 
    46 64 
    47 64 
    48 64 
    49 64 
    50 64 
    51 64 
    52 64 
    53 64 
    54 64 
    55 64 
    56 64 
    57 64 
    58 64 
    59 64 
    60 64 
    61 64 
    62 64 
    63 64 
    64 64 
    len增加且超过cap>1024时,否则以大约25%扩容,注意是大约
    28 32 
    128 128 
    228 256 
    328 512 
    428 512 
    528 1024 
    628 1024 
    728 1024 
    828 1024 
    928 1024 
    1028 1344 

     4. 字符串不能随意for

    package main
    
    import (
        "fmt"
    )
    
    func main() {
        s:="abc中国人"
        
        fmt.Println("for len是逐个unicode,也叫rune")
        for k,v:=range s {
            fmt.Println(k, string(v))
        }
        fmt.Println("for len是逐个字节, 非ascii就会乱")
        for i:=0;i<len(s);i++{
            fmt.Println(i, string(s[i]))
        }
        fmt.Println("正确用法:")
        //for len是逐个字节
        u:=[]rune(s)
        l:=len(u)
        for i:=0;i<l;i++{
            fmt.Println(i, string(u[i]))
        }
    }

    output:

    for len是逐个unicode,也叫rune
    0 a
    1 b
    2 c
    369for len是逐个字节, 非ascii就会乱
    0 a
    1 b
    2 c
    3 ä
    4 ¸
    5 ­
    6 å
    7 ›
    8 ½
    9 ä
    10 º
    11 º
    正确用法:
    0 a
    1 b
    2 c
    345

    4. map是无序的

    package main
    
    import (
        "fmt"
    )
    
    func main() {
        m:=map[string]string{
        "cc":"CC",
        "aa":"AA",
        "bb":"BB",
        }
        for k,v:=range(m){
            fmt.Println(k,v)
        }
        fmt.Println("")
        for k,v:=range(m){
            fmt.Println(k,v)
        }
        fmt.Println("")
        for k,v:=range(m){
            fmt.Println(k,v)
        }
        fmt.Println("")
        // sort 'string' key in increasing order
        fmt.Println("fix : ")
        for k,v:=range(m){
            fmt.Println(k,v)
        }    
    
        
    }

    output:

    cc CC
    aa AA
    bb BB
    
    cc CC
    aa AA
    bb BB
    
    bb BB
    cc CC
    aa AA
    
    fix : 
    cc CC
    aa AA
    bb BB

    原因:

    根据Go规范, map上的迭代顺序是不确定的,并且在程序运行之间可能会有所不同。实际上,不仅它是不确定的,而且实际上是有意随机化的。这是因为它曾经是可预测的,并且Go语言开发人员不希望人们依赖未指定的行为,所以他们有意地将其随机化,因此不可能依赖此行为。维护原插入顺序需要更多内存和cpu操作,Go设计简洁,无序意味着性能更佳,且不是所有地方都需要顺序。想排序或者按插入顺序,很容易自行实现。在Go 1.12+中,您只需打印一个map,它将自动按键排序。之所以添加它,是因为它可以轻松测试map。

    原文:https://blog.golang.org/go-maps-in-action  中  When iterating over a map with a range loop, the iteration order is not specified and is not guaranteed to be the same from one iteration to the next. If you require a stable iteration order you must maintain a separate data structure that specifies that order。

    参考 : https://tip.golang.org/doc/go1.12#fmt

    解决:package mainimport (    "fmt"    "sort"

    )
    //按插入的顺序
    type RawSortedMap struct {
      //map key类型不能是slices, maps, and functions; these types cannot be compared using ==, and may not be used as map keys. m map[
    string]interface{} keys []interface{} } func NewRawSortedMap(cap int)RawSortedMap{ m := make(map[string]interface{}, cap) keys:=make([]interface{}, cap) n:=RawSortedMap{m, keys} return n } func (r *RawSortedMap) Set(k string, v interface{}) { //通过k 快速查找
      //map不能同时read 和write,否则请加sync.RWMutex锁或者CAS .
      r.m[k] = len(r.m) //通过keys数组快速遍历 r.keys = append(r.keys, v) } func main() { m := make(map[int]string) m[1] = "a" m[2] = "c" m[0] = "b" // To store the keys in slice in sorted order var keys []int for k := range m { keys = append(keys, k) } //按数字大小的顺序 sort.Ints(keys) //按字母的顺序 //sort.Strings(keys) // To perform the opertion you want for _, k := range keys { fmt.Println("Key:", k, "Value:", m[k]) } }
  • 相关阅读:
    拥有最多糖果的孩子
    求1+2+…+n
    网络-中间代理
    Header中的Referer属性表示
    ios13.4post请求出现网错错误 network err
    10.8&10.10
    9.23&9.27
    9.16&9.19
    校内模拟赛划水报告(9.9,9.11)
    男人八题 划水题解
  • 原文地址:https://www.cnblogs.com/sunsky303/p/11807281.html
Copyright © 2020-2023  润新知