前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Gorm 语法避坑

Gorm 语法避坑

作者头像
王小明_HIT
发布2025-03-27 17:39:00
发布2025-03-27 17:39:00
4500
代码可运行
举报
文章被收录于专栏:程序员奇点程序员奇点
运行总次数:0
代码可运行
1. 方法参数是值传递,而不是引用传递,注意:slice、map、chan本身是指针,所以相当于引用传递,但数组是值传递
代码语言:javascript
代码运行次数:0
运行
复制
type user struct {
   name string
}

func main() {
   var u = user{name: "old name"}
   fmt.Println(u) // {old name}
   changeUserName(u) // 此处是值传递,所以u里的字段值不会被调用的方法所改变
   fmt.Println(u) // {old name}
}

func changeUserName(u user) {
   u.name = "new name"
}
  1. 创建给定大小的slice
代码语言:javascript
代码运行次数:0
运行
复制
// 示范1:
var arr = make([]int, 2)
fmt.Println(len(arr), cap(arr), arr) // 2, 2, [0, 0]

// 示范2:
var arr = make([]int, 0, 2)
fmt.Println(len(arr), cap(arr), arr) // 0, 2, []
3. append方法会根据slice容量决定是否创建新slice
代码语言:javascript
代码运行次数:0
运行
复制
// 示范1:
var arr = make([]int, 0)
append(arr, 10)
fmt.Println(arr) // []

arr = append(arr, 10) // 强烈推荐的写法
fmt.Println(arr) // [10]

// 示范2:
var arr = make([]int, 0, 2)
append(arr, 10)
fmt.Println(arr) // [10]
4. for-range上定义的变量,每次循环都不会改变变量的ptr,只会改变变量的值
代码语言:javascript
代码运行次数:0
运行
复制
// 示范1:
func main() {
   arr1 := []int{1, 2, 3}
   arr2 := make([]*int, 0)
   for _, v := range arr1 {
      arr2 = append(arr2, &v) // 此时取的是变量v的ptr,而不是arr1中元素的ptr
   }
   for _, v := range arr2 {
      fmt.Print(*v)
   }
}
// 最后输出:333

// 示范2:
func main() {
   arr1 := []int{1, 2, 3}
   arr2 := make([]*int, 0)
   for _, v := range arr1 {
      t := v  // 变量t每轮循环都新定义一次,分别存了arr1中的元素复制值
      arr2 = append(arr2, &t)
   }
   for _, v := range arr2 {
      fmt.Print(*v)
   }
}
// 最后输出:123
5. 数组类型是包含数组大小的,不同大小的数组类型,是不同的类型,建议开发中使用slice而不是数组
代码语言:javascript
代码运行次数:0
运行
复制
func main() {
   var arr1 [100]int
   var arr2 [200]int
   // 下面的代码是错的,arr1和arr2是不同的类型变量
   // arr2 = arr1
}
  1. 数组切slice后,会使得数组内存无法释放
代码语言:javascript
代码运行次数:0
运行
复制
// 示范1:
func notGCSample() []int{
   var arr1 [100]int
   var slice = arr1[98:100]
   return slice
}
// 调用方拿到notGCSample返回值后,[100]int所占内存不会释放,因为slice底层数组使用的还是[100]int

// 示范2:
func canGCSample() []int{
   var arr1 [100]int
   var slice = make([]int, 2)
   copy(slice, arr1[98:100])
   return slice
}
// 调用方拿到notGCSample返回值后,[100]int所占内存会释放
7. func copy(dst, src []Type)第一个参数是dst,第二个参数是src,和Java的一般方法参数设计相反
8. 零值与nil
  1. nil不是关键字
  2. 各基础类型零值:数值类型 = 0,bool = false,string = ""
  3. struct、数组的零值是包含的字段都是零值
  4. ptr零值是nil,只要不涉及解析ptr的值,其他操作都可以
  5. slice零值是nil,slice零值不能索引操作,其他操作都可以
  6. map零值是nil,map零值可看作是只读空map,不能写入
  7. chan零值是nil,读写都会阻塞,不能close 1. 被close后的chan,恒可读(select会立刻返回零值+false标志位),不能写,不能close
  8. function零值是nil,不能调用
  9. interface底层由type和val组成,只有这两个都是nil,才是nil
9. 闭包中用到的局部变量会绑定到闭包
代码语言:javascript
代码运行次数:0
运行
复制
// 示范1:
func getAddFunc() func() int {
   i := 0
   return func() int {
      i++
      return i
   }
}

func main() {
   f1 := getAddFunc()
   fmt.Println(f1()) // 1
   fmt.Println(f1()) // 2
   f2 := getAddFunc()
   fmt.Println(f2()) // 1
   fmt.Println(f2()) // 2
}

// 示范2:
func main() {
   wg := sync.WaitGroup{}
   wg.Add(5)
   for i := 0; i < 5; i++ {
      go func() {
         println(i)
         wg.Done()
      }()
   }
   wg.Wait()
}
// 最后输出:不一定,根据goroutine调度有关,可能是55555、45555、34555、35555等
  1. 值传递引用传递问题:接收器如果不是指针,也是值传递,而不是引用传递
代码语言:javascript
代码运行次数:0
运行
复制
type user struct {
   name string
}

// 接收器是值传递而不是引用传递,所以原对象的字段值不会改变
func (u user) setUserNameByVal(name string) {
   u.name = name
}

// 使用指针作为接收器,引用的是原对象,所以会修改原对象的字段值
func (u *user) setUserNameByPtr(name string) {
   u.name = name
}

func main() {
   u := user{name: "old name"}
   fmt.Println(u) // {old name}
   u.setUserNameByVal("new name by val")
   fmt.Println(u) // {old name}
   u.setUserNameByPtr("new name by ptr")
   fmt.Println(u) // {new name by ptr}
}
11. for-range不要遍历大数组,应先创建数组的slice,然后遍历slice。因为for-range上定义的变量都是值传递,如果遍历数组,值传递相当于拷贝了一份相同数据的数组
代码语言:javascript
代码运行次数:0
运行
复制
// 示范1:
var bigArr [10000]int
for i, v := range bigArr { // 此处相当于拷贝了一份bigArr
   // do something
}

// 示范2:
var bigArr [10000]int
for i, v := range bigArr[0:] { // 此处相当于拷贝了一份bigArr[0:]的slice
   // do something
}
12. 不能用'&'取址的情况
  1. const常量不能取址
  2. map的value、数组里的值不能取址(slice里的值可以取址)
13. map中的value如果是值而不是ptr,无法改变value里的字段值,可以取value里的字段值
代码语言:javascript
代码运行次数:0
运行
复制
// 示范1:
valMap := map[string][3]int{"1": {1, 2, 3}}
valMap["1"][0] = 10 // error,因为数组是值
val := valMap["1"][0] // ok

// 示范2:
ptrMap := map[string][]int{"1": {1, 2, 3}}
ptrMap["1"][0] = 10 // ok,因为slice相当于指针
val := valMap["1"][0] // ok
14. gorm2.0 First 方法回返回错误:Not Found, 但是 Find 方法没查询到数据不返回任何错误
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-06-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员奇点 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 方法参数是值传递,而不是引用传递,注意:slice、map、chan本身是指针,所以相当于引用传递,但数组是值传递
  • 3. append方法会根据slice容量决定是否创建新slice
  • 4. for-range上定义的变量,每次循环都不会改变变量的ptr,只会改变变量的值
  • 5. 数组类型是包含数组大小的,不同大小的数组类型,是不同的类型,建议开发中使用slice而不是数组
  • 7. func copy(dst, src []Type)第一个参数是dst,第二个参数是src,和Java的一般方法参数设计相反
  • 8. 零值与nil
  • 9. 闭包中用到的局部变量会绑定到闭包
  • 11. for-range不要遍历大数组,应先创建数组的slice,然后遍历slice。因为for-range上定义的变量都是值传递,如果遍历数组,值传递相当于拷贝了一份相同数据的数组
  • 12. 不能用'&'取址的情况
  • 13. map中的value如果是值而不是ptr,无法改变value里的字段值,可以取value里的字段值
    • 14. gorm2.0 First 方法回返回错误:Not Found, 但是 Find 方法没查询到数据不返回任何错误
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档