这里有一些高级技巧,你可能都不知道
感谢 https://github.com/egonelbre
作为开发人员,我们经常在想如何在考虑实用性、性能、可读性等多个因素时实现我们的想法和需求,从而找到最合适的解决方案。
我们在选择用哪种方式来表达代码中的逻辑时,所做的决定会影响软件的价值提升。同时,也会影响未来需要进行多少重构。
在做出这些选择时,最好是有很多不同的选择。
用insthead 替代 iota我想我们可以一致认为,iota 是 enum 中最差的实现之一,毫无疑问。
类型 Field 定义为 int
常量定义 (
文本字段 Field = 1
数字字段 Field = 2
)
我们创建的这个自定义整数类型与 枚举 类似,可以用作参数,甚至可以在 switch 语句中使用。
可选参数的变长参数可变参数函数可以传递任意数量的参数,包括零个参数,而且 Go 语言不支持方法重载,我们可以通过这种方法至少模拟类似的效果。
func GetRequest(address string, optTimeout...int) {
// 默认值
timeout := 30
// 如果有指定的超时时间,则使用该值
if len(optTimeout) > 0 {
timeout = optTimeout[0]
}
...
}
这个函数必须能够处理错误
这种技巧真的让人惊艳,它是一种替代我们已经厌烦的if != nil语句的方案,通过使用一个must函数,我们可以统一处理错误,从而避免重复代码。
func main() {
file := must(os.Open("./poem.txt")) // 返回 (*os.File, error)
defer file.Close()
buff := bytes.NewBuffer(make([]byte, 0))
must(file.WriteTo(buff)) // 返回 (n int64, error)
must(buff.Write([]byte("\nBut were always a rose."))) // 返回 (n int, error)
scanner := bufio.NewScanner(buff)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
}
func must[T any](v T, err error) T {
if err != nil {
log.Fatal(err)
}
return v
}
注意:此示例缺少在调用log.Fatal之前检查文件是否已正确关闭的步骤,仅用于教学目的
自定义结构体类型的行为我们能够很好地利用组合,这是Go语言中唯一的一种继承形式,通过在结构体内嵌另一个结构体,我们可以向任何结构体添加自己的方法,甚至可以向标准库中的结构体或来自外部包的结构体添加方法。
type 自定义缓冲 struct {
*bytes.Buffer
}
func (c *自定义缓冲) 读文件(filePath string) error {
f, err := os.Open(filePath)
if err != nil {
return err
}
defer f.Close() // 延迟关闭文件
if _, err = c.ReadFrom(f); err != nil {
return err
}
return nil
}
func 新建缓冲() *自定义缓冲 {
return &自定义缓冲{bytes.NewBuffer(make([]byte, 0))}
}
func main() {
buf := 新建缓冲()
buf.读文件("C:/Users/vitor/example.txt")
buf.Reset() // 重置缓冲区
}
而且从我们的 CustomBuffer 结构体里,我们可以访问 bytes.Buffer 继承来的属性和方法。
来自虚无的特纳蒂斯即使这种替代三元运算符的方法可以被视为让人难以理解的代码,这也说明我们可以通过其他方式弥补任何功能的不足。
func main() {
rows := must(QuerySales(true))
...
}
func QuerySales(过滤空值 bool) (pgx.Rows, error) {
ctx := context.Background()
// 根据过滤空值的条件,决定是否添加" AND TB_SALES.VALUE IS NOT NULL "到查询语句中
queryFilter := map[bool]string{true: " AND TB_SALES.VALUE IS NOT NULL ", false: ""}[过滤空值]
conn, err := pgx.Connect(ctx, os.Getenv("DB_CONNSTR"))
if err != nil {
// 如果连接数据库时发生错误,则返回错误信息
return nil, err
}
// 执行带有过滤条件的查询语句
return conn.Query(ctx, "SELECT * FROM TB_SALES "+queryFilter)
}
// 定义了一个通用的必须函数,确保传递的值没有错误
func must[T any](v T, err error) T {
if err != nil {
// 如果发生错误,则在日志中记录致命错误
log.Fatal(err)
}
// 返回没有错误的值
return v
}
说白了,我们只需要用一个布尔值作为键,值可以是任何类型,然后用一行代码初始化并一次性获取它的值。
和你一起走过那段旅程真是太棒了
我在写这篇帖子的时候学到了不少,也希望能在这里给你带来一些收获。
拜拜,下次见啦😜
共同学习,写下你的评论
评论加载中...
作者其他优质文章