Go 语言 12 条最佳实践.docx

上传人:b****8 文档编号:10082930 上传时间:2023-05-23 格式:DOCX 页数:19 大小:20.81KB
下载 相关 举报
Go 语言 12 条最佳实践.docx_第1页
第1页 / 共19页
Go 语言 12 条最佳实践.docx_第2页
第2页 / 共19页
Go 语言 12 条最佳实践.docx_第3页
第3页 / 共19页
Go 语言 12 条最佳实践.docx_第4页
第4页 / 共19页
Go 语言 12 条最佳实践.docx_第5页
第5页 / 共19页
Go 语言 12 条最佳实践.docx_第6页
第6页 / 共19页
Go 语言 12 条最佳实践.docx_第7页
第7页 / 共19页
Go 语言 12 条最佳实践.docx_第8页
第8页 / 共19页
Go 语言 12 条最佳实践.docx_第9页
第9页 / 共19页
Go 语言 12 条最佳实践.docx_第10页
第10页 / 共19页
Go 语言 12 条最佳实践.docx_第11页
第11页 / 共19页
Go 语言 12 条最佳实践.docx_第12页
第12页 / 共19页
Go 语言 12 条最佳实践.docx_第13页
第13页 / 共19页
Go 语言 12 条最佳实践.docx_第14页
第14页 / 共19页
Go 语言 12 条最佳实践.docx_第15页
第15页 / 共19页
Go 语言 12 条最佳实践.docx_第16页
第16页 / 共19页
Go 语言 12 条最佳实践.docx_第17页
第17页 / 共19页
Go 语言 12 条最佳实践.docx_第18页
第18页 / 共19页
Go 语言 12 条最佳实践.docx_第19页
第19页 / 共19页
亲,该文档总共19页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

Go 语言 12 条最佳实践.docx

《Go 语言 12 条最佳实践.docx》由会员分享,可在线阅读,更多相关《Go 语言 12 条最佳实践.docx(19页珍藏版)》请在冰点文库上搜索。

Go 语言 12 条最佳实践.docx

Go语言12条最佳实践

本文来自Google工程师FrancescCampoyFlores分享的幻灯片。

内容包括:

代码组织、API、并发最佳实践和一些推荐的相关资源。

 

最佳实践

维基百科的定义是:

“最佳实践是一种方法或技术,其结果始终优于其他方式。

写Go代码的目标就是:

∙简洁

∙可读性强

∙可维护性好

样例代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

typeGopherstruct{

    Name    string

    Age     int32

    FurColorcolor.Color

}

 

func(g*Gopher)DumpBinary(wio.Writer)error{

    err:

=binary.Write(w,binary.LittleEndian,int32(len(g.Name)))

    iferr==nil{

        _,err:

=w.Write([]byte(g.Name))

        iferr==nil{

            err:

=binary.Write(w,binary.LittleEndian,g.Age)

            iferr==nil{

                returnbinary.Write(w,binary.LittleEndian,g.FurColor)

            }

            returnerr

        }

        returnerr

    }

    returnerr

}

避免嵌套的处理错误

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

func(g*Gopher)DumpBinary(wio.Writer)error{

    err:

=binary.Write(w,binary.LittleEndian,int32(len(g.Name)))

    iferr!

=nil{

        returnerr

    }

    _,err=w.Write([]byte(g.Name))

    iferr!

=nil{

        returnerr

    }

    err=binary.Write(w,binary.LittleEndian,g.Age)

    iferr!

=nil{

        returnerr

    }

    returnbinary.Write(w,binary.LittleEndian,g.FurColor)

}

减少嵌套意味着提高代码的可读性

尽可能避免重复

功能单一,代码更简洁

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

typebinWriterstruct{

    w  io.Writer

    errerror

}

 

//Writewritesavalueintoitswriterusinglittleendian.

func(w*binWriter)Write(vinterface{}){

    ifw.err!

=nil{

        return

    }

    w.err=binary.Write(w.w,binary.LittleEndian,v)

}

 

func(g*Gopher)DumpBinary(wio.Writer)error{

    bw:

=&binWriter{w:

w}

    bw.Write(int32(len(g.Name)))

    bw.Write([]byte(g.Name))

    bw.Write(g.Age)

    bw.Write(g.FurColor)

    returnbw.err

}

使用类型推断来处理特殊情况

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

//Writewritesavalueintoitswriterusinglittleendian.

func(w*binWriter)Write(vinterface{}){

    ifw.err!

=nil{

        return

    }

    switchv.(type){

    casestring:

        s:

=v.(string)

        w.Write(int32(len(s)))

        w.Write([]byte(s))

    default:

        w.err=binary.Write(w.w,binary.LittleEndian,v)

    }

}

 

func(g*Gopher)DumpBinary(wio.Writer)error{

    bw:

=&binWriter{w:

w}

    bw.Write(g.Name)

    bw.Write(g.Age)

    bw.Write(g.FurColor)

    returnbw.err

}

类型推断的变量声明要短

1

2

3

4

5

6

7

8

9

10

11

12

13

//Writewritethegivenvalueintothewriterusinglittleendian.

func(w*binWriter)Write(vinterface{}){

    ifw.err!

=nil{

        return

    }

    switchv:

=v.(type){

    casestring:

        w.Write(int32(len(v)))

        w.Write([]byte(v))

    default:

        w.err=binary.Write(w.w,binary.LittleEndian,v)

    }

}

函数适配器

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

funcinit(){

    http.HandleFunc("/",handler)

}

 

funchandler(whttp.ResponseWriter,r*http.Request){

    err:

=doThis()

    iferr!

=nil{

        http.Error(w,err.Error(),http.StatusInternalServerError)

        log.Printf("handling%q:

%v",r.RequestURI,err)

        return

    }

 

    err=doThat()

    iferr!

=nil{

        http.Error(w,err.Error(),http.StatusInternalServerError)

        log.Printf("handling%q:

%v",r.RequestURI,err)

        return

    }

}

 

funcinit(){

    http.HandleFunc("/",errorHandler(betterHandler))

}

 

funcerrorHandler(ffunc(http.ResponseWriter,*http.Request)error)http.HandlerFunc{

    returnfunc(whttp.ResponseWriter,r*http.Request){

        err:

=f(w,r)

        iferr!

=nil{

            http.Error(w,err.Error(),http.StatusInternalServerError)

            log.Printf("handling%q:

%v",r.RequestURI,err)

        }

    }

}

 

funcbetterHandler(whttp.ResponseWriter,r*http.Request)error{

    iferr:

=doThis();err!

=nil{

        returnfmt.Errorf("doingthis:

%v",err)

    }

 

    iferr:

=doThat();err!

=nil{

        returnfmt.Errorf("doingthat:

%v",err)

    }

    returnnil

}

如何组织代码

 

将重要的代码放前面

版权信息,构建信息,包说明文档

Import声明,相关的包连起来构成组,组与组之间用空行隔开.。

1

2

3

4

5

6

7

import(

    "fmt"

    "io"

    "log"

 

    "

接下来代码以最重要的类型开始,以工具函数和类型结束。

 

如何编写文档

包名之前要写相关文档

1

2

3

//PackageplaygroundregistersanHTTPhandlerat"/compile"that

//proxiesrequeststothegolang.orgplaygroundservice.

packageplayground

导出的标识符(译者按:

大写的标识符为导出标识符)会出现在 godoc中,所以要正确的编写文档。

1

2

3

4

5

6

7

8

9

//Authorrepresentsthepersonwhowroteand/orispresentingthedocument.

typeAuthorstruct{

    Elem[]Elem

}

 

//TextElemreturnsthefirsttextelementsoftheauthordetails.

//Thisisusedtodisplaytheauthor'name,jobtitle,andcompany

//withoutthecontactdetails.

func(p*Author)TextElem()(elems[]Elem){

生成的文档示例

Gocode:

文档化Go代码

 

越简洁越好

或者 长代码往往不是最好的.

试着使用能自解释的最短的变量名.

∙用 MarshalIndent ,别用 MarshalWithIndentation.

别忘了包名会出现在你选择的标识符前面

∙Inpackage encoding/json wefindthetype Encoder,not JSONEncoder.

∙Itisreferredas json.Encoder.

 

有多个文件的包

需要将一个包分散到多个文件中吗?

∙避免行数非常多的文件

标准库中 net/http 包有47个文件,共计15734行.

∙拆分代码并测试

net/http/cookie.go 和 net/http/cookie_test.go 都是 http 包的一部分.

测试代码 只有 在测试时才会编译.

∙多文件包的文档编写

如果一个包中有多个文件,可以很方便的创建一个 doc.go 文件,包含包文档信息.

让包可以”goget”到

一些包将来可能会被复用,另外一些不会.

定义了一些网络协议的包可能会在开发一个可执行命令时复用.

 

接口

你需要什么

让我们以之前的Gopher类型为例

1

2

3

4

5

typeGopherstruct{

    Name    string

    Age     int32

    FurColorcolor.Color

}

我们可以定义这个方法

1

func(g*Gopher)DumpToFile(f*os.File)error{

但是使用一个具体的类型会让代码难以测试,因此我们使用接口.

1

func(g*Gopher)DumpToReadWriter(rwio.ReadWriter)error{

进而,由于使用的是接口,我们可以只请求我们需要的.

1

func(g*Gopher)DumpToWriter(fio.Writer)error{

让独立的包彼此独立

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

import(

    "

    "

 

 //Parsethetextintoanexecutablefunction.

    f,err:

=parser.Parse(text)

    iferr!

=nil{

        log.Fatalf("parse%q:

%v",text,err)

    }

 

    //Createanimageplottingthefunction.

    m:

=drawer.Draw(f,*width,*height,*xmin,*xmax)

 

    //Encodetheimageintothestandardoutput.

    err=png.Encode(os.Stdout,m)

    iferr!

=nil{

        log.Fatalf("encodeimage:

%v",err)

    }

解析

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

typeParsedFuncstruct{

    textstring

    evalfunc(float64)float64

}

 

funcParse(textstring)(*ParsedFunc,error){

    f,err:

=parse(text)

    iferr!

=nil{

        returnnil,err

    }

    return&ParsedFunc{text:

text,eval:

f},nil

}

 

func(f*ParsedFunc)Eval(xfloat64)float64{returnf.eval(x)}

func(f*ParsedFunc)String()string        {returnf.text}

描绘

1

2

3

4

5

6

7

8

import(

    "image"

 

    "

 

//DrawdrawsanimageshowingarenderingofthepassedParsedFunc.

funcDrawParsedFunc(fparser.ParsedFunc)image.Image{

使用接口来避免依赖.

import"image"

//Functionrepresentadrawablemathematicalfunction.

typeFunctioninterface{

Eval(float64)float64

}

//DrawdrawsanimageshowingarenderingofthepassedFunction.

funcDraw(fFunction)image.Image{

测试

使用接口而不是具体类型让测试更简洁.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

packagedrawer

 

import(

    "math"

    "testing"

 

typeTestFuncfunc(float64)float64

 

func(fTestFunc)Eval(xfloat64)float64{returnf(x)}

 

var(

    ident=TestFunc(func(xfloat64)float64{returnx})

    sin  =TestFunc(math.Sin)

 

funcTestDraw_Ident(t*testing.T){

    m:

=Draw(ident)

    //Verifyobtainedimage.

在接口中避免并发

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

funcdoConcurrently(jobstring,errchanerror){

    gofunc(){

        fmt.Println("doingjob",job)

        time.Sleep(1*time.Second)

        err<-errors.New("somethingwentwrong!

")

    }()

}

 

funcmain(){

    jobs:

=[]string{"one","two","three"}

 

    errc:

=make(chanerror)

    for_,job:

=rangejobs{

        doConcurrently(job,errc)

    }

    for_=rangejobs{

        iferr:

=<-errc;err!

=nil{

            fmt.Println(err)

        }

    }

}

如果我们想串行的使用它会怎样?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

funcdo(jobstring)error{

    fmt.Println("doingjob",job)

    time.Sleep(1*time.Second)

    returnerrors.New("somethingwentwrong!

")

}

 

funcmain(){

    jobs:

=[]string{"one","two","three"}

 

    errc:

=make(chanerror)

    for_,job:

=rangejobs{

        gofunc(jobstring){

            errc<-do(job)

        }(job)

    }

    for_=rangejobs{

        iferr:

=<-errc;err!

=nil{

            fmt.Println(err)

        }

    }

}

暴露同步的接口,这样异步调用这些接口会简单.

 

并发的最佳实践

 

使用goroutines管理状态

使用chan或者有chan的结构体和goroutine通信

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

typeServerstruct{quitchanbool}

 

funcNewServer()*Server{

    s:

=&Server{make(chanbool)}

    gos.run()

    returns

}

 

func(s*Server)run(){

    for{

        select{

        case<-s.quit:

            fmt.Println("finishingtask")

            time.Sleep(time.Second)

            fmt.Println("taskdone")

            s.quit<-true

            return

        case<-time.After(tim

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > PPT模板 > 其它模板

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2