To err is human,to forgive divine.
-Alexander Pope
01
循环中易犯的错误
1.1
使用循环迭代变量的指针
in := []int{1, 2, 3}var out []*intfor _, v := range in {out = append(out, &v)}fmt.Println("Values:", *out[0], *out[1], *out[2])fmt.Println("Addresses:", out[0], out[1], out[2])
结果输出:
Values: 3 3 3Addresses: 0xc0000a4008 0xc0000a4008 0xc0000a4008
in := []int{1, 2, 3}var out []*intfor _, v := range in {v := vout = append(out, &v)}fmt.Println("Values:", *out[0], *out[1], *out[2])fmt.Println("Addresses:", out[0], out[1], out[2])
PS:也可以直接根据range返回第一个参数作为数组索引下标 拿值
循环中goroutine使用循环迭代变量也会存在同样的问题:
list := []int{1, 2, 3}for _, v := range list {go func() {fmt.Printf("%d ", v)}()}
输出结果:
3 3 3
1.2
循环中调用WaitGroup.Wait
var wg sync.WaitGroupwg.Add(len(tasks))for _, t := range tasks {go func(t *task) {defer wg.Done()}(t)// wg.Wait()}wg.Wait()
1.3
循环中使用defer
var mutex sync.Mutextype Person struct {Age int}persons := make([]Person, 10)for _, p := range persons {mutex.Lock()// defer mutex.Unlock()p.Age = 13mutex.Unlock()}
var mutex sync.Mutextype Person struct {Age int}persons := make([]Person, 10)for _, p := range persons {func() {mutex.Lock()defer mutex.Unlock()p.Age = 13}()}
02
发送到一个无保证的channel
func doReq(timeout time.Duration) obj {// ch :=make(chan obj)ch := make(chan obj, 1)go func() {obj := do()ch <- result} ()select {case result = <- ch :return resultcase<- time.After(timeout):return nil}}
-
将ch从无缓冲channel改成有缓冲channel,这样子Goroutine将永远可以发送结果数据,即使父节点已经退出
-
select中使用default语句,如果没有goroutine收到ch,则会发送默认情况。尽管这种方案不是总能生效。
...select {case ch <- result:default:}...
03
不使用接口
type Reader interface {Read(p []byte) (n int, err error)}type Writer interface {Write(p []byte) (n int, err error)}
func (o *obj)Save(file os.File) error
func (o *obj)Save(w io.Writer) error
04
糟糕的结构体字段排序
type BadOrderedPerson struct {Veteran bool // 1 byteName string // 16 byteAge int32 // 4 byte}type OrderedPerson struct {Name stringAge int32Veteran bool}
-
BadOrderedPerson 类型分配了32bytes
-
OrderedPerson类型分配了24bytes
padding = (align - (offset mod align)) mod alignaligned = offset + padding= offset + ((align - (offset mod align)) mod align)
type BadOrderedPerson struct {Veteran bool // 1 byte_ [7]byte // 7 byte: padding for alignmentName string // 16 byteAge int32 // 4 byte_ struct{} // to prevent unkeyed literals// zero sized values, like struct{} and [0]byte occurring at// the end of a structure are assumed to have a size of one byte.// so padding also will be addedd here as well.}type OrderedPerson struct {Name stringAge int32Veteran bool_ struct{}}
05
测试中不使用race detector
$ go test -race pkg // to test the package$ go run -race pkg.go // to run the source file$ go build -race // to build the package$ go install -race pkg // to install the package
WARNING: DATA RACERead by goroutine 185:net.(*pollServer).AddFD()src/net/fd_unix.go:89 +0x398net.(*pollServer).WaitWrite()src/net/fd_unix.go:247 +0x45net.(*netFD).Write()src/net/fd_unix.go:540 +0x4d4net.(*conn).Write()src/net/net.go:129 +0x101net.func·060()src/net/timeout_test.go:603 +0xafPrevious write by goroutine 184:net.setWriteDeadline()src/net/sockopt_posix.go:135 +0xdfnet.setDeadline()src/net/sockopt_posix.go:144 +0x9cnet.(*conn).SetDeadline()src/net/net.go:161 +0xe3net.func·061()src/net/timeout_test.go:616 +0x3edGoroutine 185 (running) created at:net.func·061()src/net/timeout_test.go:609 +0x288Goroutine 184 (running) created at:net.TestProlongTimeout()src/net/timeout_test.go:618 +0x298testing.tRunner()src/testing/testing.go:301 +0xe8
推荐阅读

文章评论