go中常见的错误-以及泛型

https://github.com/teivah/100-go-mistakes#table-of-contents
nil Map

map记得要make初始化, slice可以不用初始化!

go 复制代码
func main() {
//assignment to nil map
var course map[string]string //如果不初始化,就会为nil
 course["name"] = "go体系课"
}

结构体空指针

空结构体和结构体空指针可不一样

go 复制代码
type Course struct {
 Name string
 Desc string
}
func (c *Course) String() float64 {
 return c.Name + c.Desc
}
func main() {
 var c *Course //无效的内存地址或空指针解引用
 fmt.Println(c.String())
}
//结构体空指针 指针类型一定要初始化,否则nil
//var c *Couser 
c := &Couser{} // new(Couser)

使用对循环迭代器变量的引用 - 大坑!

在 Go 中,循环迭代器变量是一个单一的变量,在每个循环迭代中取不同的值。这如果使用不当,可能会导致非预期的行为。

go 复制代码
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])
}
go 复制代码
func main() {

	var out []*int
	//for循环的临时变量会复用
	for i := 0; i < 3; i++ {
		out = append(out, &i)
	}
	fmt.Println(out) //[0xc00000a0c8 0xc00000a0c8 0xc00000a0c8]
	for _, value := range out {
		fmt.Println(*value) //3 3 3
	}
}

解决办法

go 复制代码
func main() {
 var out []*int
 for i := 0; i < 3; i++ {
 tmpi := i
 out = append(out, &tmpi)
 }
 fmt.Println("Values:", *out[0], *out[1], *out[2])
 fmt.Println("Addresses:", out[0], out[1], out[2])
}

原因是:在每次迭代中,我们将 i 的地址追加到 out 切片中,但由于它是同一个变量,我们实际上追加的是相同的地址,该地址最终包含分配给 i 的最后一个值。所以只需要拷贝一份,让两者脱离关联就可以了。同样的,如果这里是for循环然后启动多个goroutine, 如下:

go 复制代码
package main
import (
	"fmt"
	"strconv"
	"time"
)

func main() {
	goodsID := []uint64{1, 2, 3, 4, 5}
	for _, id := range goodsID {
		go func() {
			fmt.Println("正在查询商品:" + strconv.Itoa(int(id)))
		}()
	}
	time.Sleep(time.Second * 5)
}

注意:这种bug在goland中一般会提醒,

常用的解决办法:

go 复制代码
import (
	"fmt"
	"strconv"
	"time"
)

func main() {
	goodsID := []uint64{1, 2, 3, 4, 5}
	for _, id := range goodsID {
		tmp := id
		go func() {
			fmt.Println("正在查询商品:" + strconv.Itoa(int(tmp)))
		}()
	}
	time.Sleep(time.Second * 5)
}
go 复制代码
package main

import (
	"fmt"
	"strconv"
	"time"
)

func main() {
	goodsID := []uint64{1, 2, 3, 4, 5}
	for _, id := range goodsID {
		//值传递
		go func(id uint64) {
			fmt.Println("正在查询商品:" + strconv.Itoa(int(id)))
		}(id)
	}
	time.Sleep(time.Second * 5)
}

go如何使用泛型

go 复制代码
package main

func Add[T int | int32 | float32 | float64 | uint64](a, b T) T {
	return a + b
}

// IAdd  没有泛型之前
func IAdd(a, b interface{}) interface{} {
	switch a.(type) {
	case int:
		return a.(int) + b.(int)

	case int32:
		return a.(int32) + b.(int32)
	case float32:
		return a.(float32) + b.(float32)

	}
	return nil
}

func main() {

	//print(Add[float32](1.2, 2.2))
	t := IAdd(1, 2).(int)
	print(t)
}

泛型的常见用法

go 复制代码
package main

type Mymap[KEY int | string, VALUE float32 | float64] map[KEY]VALUE

type Man struct {
}

type Woman struct {
}

type Company[T Man | Woman] struct {
	Name string
	CEO  T
}

type MyChannel[T int | string] chan T

// WowStruct 类型嵌套
type WowStruct[T string | int, S []T] struct {
	A T
	B S
}

func main() {
	/*m:=Mymap[int,float32]{

	}*/

	//company := Company[Man]{
	//	Name: "chengpeng",
	//	CEO:  Man{},
	//}
	//
	//company1 := Company[Woman]{
	//	Name: "chengpeng",
	//	CEO:  Man{},
	//}

	var c MyChannel[string]
}

泛型的错误用法

go 复制代码
//错误用法1 类型参数不能单独使用
//type CommonType[T int | string] T

type CommonType[T int | string] []T

//错误用法2 无效的数组绑定 'T *int | string',必须是一个常量表达式
//type CommonType1[T *int | string] []T

type CommonType1[T interface{ *int } | string] []T

匿名接口体不支持泛型--错误用法3

go 复制代码
test:= struct[t int|string] {
	Name string
	Age int
}{}

匿名函数不支持泛型--错误用法3

go 复制代码
fn := func[T int | float64](a, b T) {
}

泛型不支持switch断言,但是可以用反射去做做法不提倡---错误用法4

go 复制代码
func Add1[T int | int32 | float32 | float64 | uint64](a, b T) T {
	v := reflect.ValueOf(a)

	switch v.Kind() {
	case reflect.Int:
		print("int type")
	}
	return a + b
}
相关推荐
winks3几秒前
Spring Task的使用
java·后端·spring
Null箘2 分钟前
从零创建一个 Django 项目
后端·python·django
云空6 分钟前
《解锁 Python 数据挖掘的奥秘》
开发语言·python·数据挖掘
秋意钟11 分钟前
Spring新版本
java·后端·spring
青莳吖16 分钟前
Java通过Map实现与SQL中的group by相同的逻辑
java·开发语言·sql
Buleall23 分钟前
期末考学C
java·开发语言
重生之绝世牛码25 分钟前
Java设计模式 —— 【结构型模式】外观模式详解
java·大数据·开发语言·设计模式·设计原则·外观模式
小蜗牛慢慢爬行31 分钟前
有关异步场景的 10 大 Spring Boot 面试问题
java·开发语言·网络·spring boot·后端·spring·面试
Algorithm157641 分钟前
云原生相关的 Go 语言工程师技术路线(含博客网址导航)
开发语言·云原生·golang
shinelord明1 小时前
【再谈设计模式】享元模式~对象共享的优化妙手
开发语言·数据结构·算法·设计模式·软件工程