5個(gè)golang中易犯的錯(cuò)誤
To err is human,to forgive divine.
? ? ? ? ? ? ? ? -Alexander Pope
01
循環(huán)中易犯的錯(cuò)誤
1.1
使用循環(huán)迭代變量的指針
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])
結(jié)果輸出:
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:也可以直接根據(jù)range返回第一個(gè)參數(shù)作為數(shù)組索引下標(biāo) 拿值
循環(huán)中g(shù)oroutine使用循環(huán)迭代變量也會(huì)存在同樣的問題:
list := []int{1, 2, 3}for _, v := range list {go func() {fmt.Printf("%d ", v)}()}
輸出結(jié)果:
3 3 31.2
循環(huán)中調(diào)用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
循環(huán)中使用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
發(fā)送到一個(gè)無保證的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將永遠(yuǎn)可以發(fā)送結(jié)果數(shù)據(jù),即使父節(jié)點(diǎn)已經(jīng)退出
select中使用default語句,如果沒有g(shù)oroutine收到ch,則會(huì)發(fā)送默認(rèn)情況。盡管這種方案不是總能生效。
...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) errorfunc?(o?*obj)Save(w io.Writer) error04
糟糕的結(jié)構(gòu)體字段排序
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
測(cè)試中不使用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
推薦閱讀
評(píng)論
圖片
表情
