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
}
相关推荐
H.莓飛20 分钟前
【Linux】自主 Shell
linux·运维·服务器·c语言·开发语言·visual studio
熊猫钓鱼>_>23 分钟前
Kotlin Multiplatform for OpenHarmony 实战:kotlinx-coroutines 结构化并发适配
开发语言·kotlin·agent·harmonyos·openharmony·适配·华为云码道
七夜zippoe29 分钟前
Spring Boot 接通义千问:从拿 Key 到第一个对话接口跑通(保姆级)
java·spring boot·后端
SimonKing30 分钟前
别再花钱调 OCR 接口了!这个国产开源工具,免费还能离线跑
java·后端·程序员
Nebula_g30 分钟前
SpringBoot企业级实战项目—云禾外卖—SpringBoot常用注解解析
java·网络·数据库·spring boot·后端·spring·javase
沫璃染墨36 分钟前
《Qt从零入门系列(十四):QThread多线程详解——从线程创建到客户端阻塞处理》
开发语言·c++·笔记·qt·ui·交互·线程
hixiong1231 小时前
C# 使用 ZXingCpp.Angle 进行条码、二维码识别
开发语言·c#·扫码
云和数据.ChenGuang1 小时前
AI 工程师相关就业岗位(细分,偏工程落地,由底层到上层)
服务器·开发语言·人工智能·python
爱读书的小胖1 小时前
Codewars:Last digit of a large number(C)解题分析
c语言·开发语言·r语言
码途行者1 小时前
处理超时未支付订单:两套轻量化方案,附 PHP 极简实现
开发语言·redis·php