加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

go语言常见陷阱

发布时间:2020-12-16 09:40:16 所属栏目:大数据 来源:网络整理
导读:go语言常见陷阱 (英文原文)[https://deadbeef.me/2018/01/go-gotchas] Range 在golang中我们经常用range来遍历slice或chan,如果要更改slice中的成员应该怎么做?下面代码要把动物园中所有动物的腿变为999 type Animal struct { name string legs int } func

go语言常见陷阱

(英文原文)[https://deadbeef.me/2018/01/go-gotchas]

Range

在golang中我们经常用range来遍历slice或chan,如果要更改slice中的成员应该怎么做?下面代码要把动物园中所有动物的腿变为999

type Animal struct {
    name string
    legs int
}

func main() {
  zoo := []Animal{ Animal{ "Dog", 4 },Animal{ "Chicken", 2 },Animal{ "Snail", 0 },}

  fmt.Printf("-> Before update %vn",zoo)

  for _,animal := range zoo {
    // Oppps! `animal` is a copy of an element 
    animal.legs = 999
  }

  fmt.Printf("n-> After update %vn",zoo)
}

打印结果如下:

-> Before update [{Dog 4} {Chicken 2} {Snail 0}]
-> After update [{Dog 4} {Chicken 2} {Snail 0}]

原因在于range遍历slice是,value是slice中值的拷贝,所有无法真正修改slice。

解决方法

for idx,_ := range zoo {
  zoo[idx].legs = 999
}

三个相连的…

在c语言中,我们使用…表示可变参数,用法如下

int add_em_up (int count,...) {
  ...
  va_start (ap,count);         /* Initialize the argument list */
  for (i = 0; i < count; i++)
      sum += va_arg(ap,int);   /* Get the next argument value */
  va_end (ap);                  /* Clean up */
  return sum
}

在golang中有所不同

func myFprint(format string,a ...interface{}) {
    if len(a) == 0 {
        fmt.Printf(format)
    } else {
        // ?? `a` should be `a...`
        fmt.Printf(format,a)
        // ?
        fmt.Printf(format,a...)
    }
}

func main() {
    myFprint("%s : line %dn","file.txt", 49)
}

打印结果

[file.txt %!s(int=49)] : line %!d(MISSING)
file.txt : line 49

在go中,可变参数被编译器转换为slice

所以对于上面的例子,要打印可变参数也可以用下面的方法:

// `a` is just a slice!
for _,elem := range a {
    fmt.Println(elem)
}

Slice

在python中对一个列表使用slice,结果会产生一个新的列表

a = [1,2,3]
b = a[:2]           # 产生一个新的list
b[0] = 999
>>> a
[1,3]
>>> b
[999,2]

但是在golang中,slice其实只是指向原slice的一个指针,对原slice或新的slice修改都会对双方产生同样修改。

func main() {
  data := []int{1,2,3}
  slice := data[:2]
  slice[0] = 999

  fmt.Println(data)
  fmt.Println(slice)
}

打印结果

[999 2 3]
[999 2]

在golang中如何根据已有的slice创建一个copy

// Option #1
// appending elements to a nil slice
// `...` changes slice to arguments for the variadic function `append`
a := append([]int{},data[:2]...)

// Option #1
// Create slice with length of 2
// copy(dest,src)
a := make([]int, 2)
copy(a,data[:2]

根据StackOverflow,append要比make+copy更快一些。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读