结论就是:
当我们创建一个函数时,我们的默认行为应该是使用值而不是指针 。仅当我们想要共享变量时才应使用指针 。
最后:
如果我们遇到性能问题,一种可能的优化可能是检查指针在某些特定情况下是否有帮助 。使用以下命令可以知道编译器何时将变量转移到堆中:go build -gcflags "-m -m" 。(内存逃逸)
3、中断 for/switch 或 for/select我们看下下面的代码会发生什么:
package mainfunc f() bool { return true}func main() { for {switch f() {case true:breakcase false:// Do something} }}
我们将调用 break 语句 。但是,这会破坏 switch 语句,而不是 for 循环 。
相同的情况还会出现在fo/select中,像下面这样:
package mainimport ( "context" "time")func main() { ch := make(chan struct{}) ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() for {select {case <-ch:// Do somethingcase <-ctx.Done():break} }}
虽然调用了break,但是还是会陷入死循环 。break 与 select 语句有关,与 for 循环无关 。
打破 for/switch 或 for/select 的,一种方案是直接return结束整个函数,下面如果还有代码不会被执行 。
package mainimport ( "context" "fmt" "time")func main() { ch := make(chan struct{}) ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() for {select {case <-ch:// Do somethingcase <-ctx.Done():return} }// 这里不会执行 fmt.Println("done")}
还有一种方案是使用中断标记
package mainimport ( "context" "fmt" "time")func main() { ch := make(chan struct{}) ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel()loop: for {select {case <-ch:// Do somethingcase <-ctx.Done():break loop} }// 会继续往下执行 fmt.Println("done")}
4、错误管理一个错误应该只处理一次 。记录错误就是处理错误 。因此,应该记录或传播错误 。
我们可能希望为错误添加一些上下文并具有某种形式的层次结构 。
让我们看一个接口请求数据库的例子,我们分为接口层,service层和类库层 。我们希望返回的层次结构像下面这样:
unable to serve HTTP POST request for id 1 |_ unable to insert customer|_ unable to commit transaction
如果我们使用 pkg/errors,我们可以这样做:
package mainimport ( "fmt" "Github.com/pkg/errors")func postHandler(id int) string { err := insert(id) if err != nil {fmt.Printf("unable to serve HTTP POST request for id %dn", id)return `{ok: false}` } return `{ok: true}`}func insert(id int) error { err := dbQuery(id) if err != nil {return errors.Wrapf(err, "unable to insert customer") } return nil}func dbQuery(id int) error { // Do something then fail return errors.New("unable to commit transaction")}func main() { res := postHandler(1) fmt.Println(res)}
初始错误(如果不是由外部库返回)可以使用 errors.New 创建 。service层 insert 通过向其添加更多上下文来包装此错误 。然后,接口层通过记录错误来处理错误 。每个级别都返回或处理错误 。
例如,我们可能还想检查错误原因本身以实现重试 。假设我们有一个来自处理数据库访问的外部库的 db 包 。这个库可能会返回一个名为 db.DBError 的暂时(临时)错误 。要确定是否需要重试,我们必须检查错误原因:
package mainimport ( "fmt" "github.com/pkg/errors")type DbError struct { msg string}func (e *DbError) Error() string { return e.msg}func postHandler(id int) string { err := insert(id) if err != nil {errCause := errors.Cause(err)if _, ok := errCause.(*DbError); ok {fmt.Println("retry")} else {fmt.Printf("unable to serve HTTP POST request for id %dn", id)return `{ok: false}`} } return `{ok: true}`}func insert(id int) error { err := dbQuery(id) if err != nil {return errors.Wrapf(err, "unable to insert customer") } return nil}func dbQuery(id int) error { // Do something then fail return &DbError{"unable to commit transaction"}}func main() { res := postHandler(1) fmt.Println(res)}
这是使用errors.Cause完成的,它也来自pkg/errors 。(可以通过errors.Cause检查 。errors.Cause 将递归检索没有实现causer 的最顶层错误,这被认为是原始原因 。)
有时候也会有人这么用 。例如,检查错误是这样完成的:
package mainimport ( "fmt" "github.com/pkg/errors")type DbError struct { msg string}func (e *DbError) Error() string { return e.msg}func postHandler(id int) string { err := insert(id) if err != nil {switch err.(type) {default:fmt.Printf("unable to serve HTTP POST request for id %dn", id)return `{ok: false}`case *DbError:fmt.Println("retry")} } return `{ok: true}`}func insert(id int) error { err := dbQuery(id) if err != nil {return errors.Wrapf(err, "unable to insert customer") } return nil}func dbQuery(id int) error { // Do something then fail return &DbError{"unable to commit transaction"}}func main() { res := postHandler(1) fmt.Println(res)}
推荐阅读
- 沈腾|又帅又好笑!沈腾瘦身成功亮相华表奖 大秀俄语
- 删除|回顾:妻子手机蓝牙忘关,车内自动播放的一条语音,毁了5年婚姻!
- ChatGPT进入iPhone时刻:“Chat感”更强、可使用多种语言
- 周冬雨|周冬雨戛纳造型惨遭网友嫌弃,网友言语粗鄙,但说的好有道理!
- |陈萌独自去做产假,手拿B超单沉默不语,发文24字评价朱小伟
- 秋瓷炫|浪姐4:初代唱跳,周深铁粉孙悦拉满团魂,秋瓷炫韩语rap实力圈粉
- |同是中国儿媳都生了娃,吉娜在家说4种语言,秋瓷炫教儿子说韩语
- |落跑甜心女主官宣被女友求婚,言语幸福声援女同,称非第一次被求婚引争议
- 香菇可以泡一夜吗
- 吴千语|恋上百亿富三代,成功挤身名媛圈,戛纳生图曝光吴千语的真实状态