Gorm 语法避坑
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"
}
- 创建给定大小的slice
// 示范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
}
- 数组切slice后,会使得数组内存无法释放
// 示范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
- nil不是关键字
- 各基础类型零值:数值类型 = 0,bool = false,string = ""
- struct、数组的零值是包含的字段都是零值
- ptr零值是nil,只要不涉及解析ptr的值,其他操作都可以
- slice零值是nil,slice零值不能索引操作,其他操作都可以
- map零值是nil,map零值可看作是只读空map,不能写入
- chan零值是nil,读写都会阻塞,不能close 1. 被close后的chan,恒可读(select会立刻返回零值+false标志位),不能写,不能close
- function零值是nil,不能调用
- 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等
- 值传递引用传递问题:接收器如果不是指针,也是值传递,而不是引用传递
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. 不能用'&'取址的情况
- const常量不能取址
- 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 删除gorm变量数组语法指针发布者:admin,转转请注明出处:http://www.yc00.com/web/1748124685a4735194.html
评论列表(0条)