为了账号安全,请及时绑定邮箱和手机立即绑定

成为GoLang高手:你不可不知的高级技巧

这里有一些高级技巧,你可能都不知道

感谢 https://github.com/egonelbre

作为开发人员,我们经常在想如何在考虑实用性、性能、可读性等多个因素时实现我们的想法和需求,从而找到最合适的解决方案。

我们在选择用哪种方式来表达代码中的逻辑时,所做的决定会影响软件的价值提升。同时,也会影响未来需要进行多少重构。

在做出这些选择时,最好是有很多不同的选择。

用insthead 替代 iota

我想我们可以一致认为,iotaenum 中最差的实现之一,毫无疑问。

类型 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  
}

说白了,我们只需要用一个布尔值作为键,值可以是任何类型,然后用一行代码初始化并一次性获取它的值。

和你一起走过那段旅程真是太棒了

我在写这篇帖子的时候学到了不少,也希望能在这里给你带来一些收获。

拜拜,下次见啦😜

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号

举报

0/150
提交
取消