golang后端开发笔记

  1. golang语言问题

golang后端开发笔记

之前的小程序使用的是原生的云开发,方便固然方便但实际上并没有做太多的工作,也不需要考虑过多的问题,这次用golang重写后端算是对自身的一个挑战,从头梳理后端开发的基本内容并且深入理解golang语言和网络相关的知识。 主要使用gin+gorm+Mysql+Redis

golang语言问题

slice传参

修改slice中struct的问题

在修改slice中的数据时,自然会想到用for range循环。但在实际使用的过程中需要注意golang语言中range循环的一些特性。下面给出一个例子

1
2
3
4
5
6
func main() {
    slice := []int{10, 20, 30, 40}
    for index, value := range slice {
        fmt.Printf("value = %d , value-addr = %x , slice-addr = %x\n", value, &value, &slice[index])
    }
}

这里value如果代表的是slice切片中的各个数据,那么value的地址理应随着循环发生变化,但是实际上输出的结果为

value = 10 , value-addr = c4200aedf8 , slice-addr = c4200b0320

value = 20 , value-addr = c4200aedf8 , slice-addr = c4200b0328

value = 30 , value-addr = c4200aedf8 , slice-addr = c4200b0330

value = 40 , value-addr = c4200aedf8 , slice-addr = c4200b0338

显然value的地址并没有发生变化,这说明value本身是一个结构,在循环过程中只是将对应的值拷贝到了value当中,value并不是指向切片中对应值的指针。 关于这点,在golang的官方wiki中的CommonMistakes中给出了相关的说明,官方给出的例子如下

1
2
3
4
5
6
7
8
func main() {
	var out []*int
	for i := 0; i < 3; i++ {
		out = append(out, &i)
	}
	fmt.Println("Values:", *out[0], *out[1], *out[2])
	fmt.Println("Addresses:", out[0], out[1], out[2])
}

官方给出的例子也非常有趣,这个例子实际上的输出结果为

Values: 3 3 3

Addresses: 0x40e020 0x40e020 0x40e020

在Go中,循环过程中的循环迭代器如第二个例子中的i以及第一个例子中的value都是一个单独的变量,在循环进行过程中会将不同的值拷贝给这个变量,这样的好处在于只需要为这个变量申请一次内存空间,之后改变它的值就可以了。但是因为只是将不同的值赋给这一个变量,该变量的地址一直没有变化,这时我们将该变量的地址放入out切片中,则最后通过解引用取得的值是该变量最后一次被赋予的值。即循环过程可以理解为

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
func main(){
  var new_variable int
  var out []*int
  // 模拟循环的过程
  new_variable = 1
  append(out, &new_variable)
  new_variable = 2
  append(out, &new_variable)
  new_variable = 3
  append(out, &new_variable)
  }

这样一来这个循环最后的结果就很容易理解了。这个问题看似是一个小问题,但在实际编写程序的过程中常常会因疏忽这个问题而出错,比如在遍历一个结构体切片时,赋值给迭代器的成员变量,循环结束后会发现结构体切片中的值并没有改变,实际上应该使用诸如out[i]这种通过下标访问的形式修改切片中的值,而不是使用迭代器。这点要时刻注意

使用的三方库更新问题

使用gorm时使用它的sql表达式更新功能时发现会出现莫名其妙的bug, 更新表达式是减但是得到的sql语句是直接置零. 让我非常不解, 在研究文档的过程中, 我偶然发现当前的gorm文档是gorm 2.0,而我之前导入的包是gorm 1.0的包. 因此之前的1.0中可能并没有实现这个功能, 非常的尴尬. 将导入的包切换为gorm 2.0后一切功能正常.

这提醒我们在使用三方库时, 可能三方库会因为更新等原因有一些api上的重大变化, 要注意使用的包的版本.