跳过正文

Go语言技巧

·693 字
目录

Defer两阶段延迟执行
#

记录函数执行时间

package main

import (
	"log"
	"time"
)

func main() {
	defer TrackingTime()()

	time.Sleep(time.Millisecond * 100)

	log.Println("执行结束")
}

func TrackingTime() func() {
	now := time.Now()
	log.Printf("开始时间: %d\n", now.UnixMilli())
	return func() {
		cost := time.Since(now).Milliseconds()
		log.Printf("耗时: %dms\n", cost)
	}
}

链式调用
#

常见例如gorm包等

package main

import (
	"errors"
	"fmt"
)

func main() {
	p := &Person{}
	err := p.SetName("name").SetAge(18).Error()
	if err != nil {
		fmt.Printf("initialize person failed, %v\n", err)
	} else {
		fmt.Printf("%+v\n", p)
	}
}

type Person struct {
	Name string
	Age  int
	Err  error
}

func (p *Person) SetName(name string) *Person {
	if p.Err == nil {
		p.Name = name
	}

	// 错误处理
	p.SetError(errors.New("xxx"))

	return p
}

func (p *Person) SetAge(age int) *Person {
	if p.Err == nil {
		p.Age = age
	}

	return p
}

func (p *Person) SetError(err error) *Person {
	p.Err = err

	return p
}

func (p *Person) Error() error {
	return p.Err
}

切片转数组
#

go 1.20开始可以直接将切片转换为数组

package main

import "fmt"

func main() {
	a := []int{1, 2, 3, 4}
	// b := [3]int(a[:3]) // go1.20+
	b := *(*[3]int)(a[:3]) // go1.19-, 注意切片长度需大于等于数组b的长度

	fmt.Printf("type: %T, value: %v\n", b, b)
}

错误合并
#

wrap
#

go1.13增加了errors.Unwrap()、errors.Is()、errors.As()方法

fmt.Errorf()方法支持%w来前套错误

package main

import (
	"errors"
	"fmt"
)

func main() {
	err1 := errors.New("error1")
	err2 := fmt.Errorf("error2: [%w]", err1)
	fmt.Println(err2) // error2: error1
	fmt.Println(errors.Unwrap(err2)) // error1
}

errors.As(err error, target any) bool

查找error中是否嵌套了target类型的错误,如果存在则将前套的错误赋值给target

package main

import (
	"errors"
	"fmt"
	"io/fs"
	"os"
)

func main() {
	if _, err := os.Open("non-existing"); err != nil {
		var pathError *fs.PathError
		if errors.As(err, &pathError) {
			fmt.Println("Failed at path:", pathError.Path)
		} else {
			fmt.Println(err)
		}
	}
}

join
#

go1.20 加了errors.Join()方法,并修改了errors.Is()、errors.As()方法

package main

import (
	"errors"
	"fmt"
)

func main() {
	err1 := errors.New("err1")
	err2 := errors.New("err2")
	err := errors.Join(err1, err2)
	fmt.Println(err)

	if errors.Is(err, err1) { // true
		fmt.Println("err is err1")
	}
	if errors.Is(err, err2) { // true
		fmt.Println("err is err2")
	}
}

判断interface{}是否真的为nil
#

package main

import (
    "fmt"
    "reflect"
)

func main() {
  var x interface{}
  var y *int = nil
  x = y

  if x != nil {
    fmt.Println("x != nil") // x != nil
  } else {
    fmt.Println("x == nil")
  }

  fmt.Println(x) // <nil>

  fmt.Println(IsNil(x)) // true
}

func IsNil(x interface{}) bool {
  if x == nil {
    return true
  }

  return reflect.ValueOf(x).IsNil()
}