golang

32
Introduction Formatting Commentary Names Semicolons Control structures Functions Effective Go[1] Jongseok Choi Effective Go Jongseok Choi 1 / 31

Upload: jongseok-choi

Post on 12-Apr-2017

90 views

Category:

Engineering


0 download

TRANSCRIPT

Page 1: Golang

Introduction Formatting Commentary Names Semicolons Control structures Functions

Effective Go[1]

Jongseok Choi

Effective Go Jongseok Choi 1 / 31

Page 2: Golang

Introduction Formatting Commentary Names Semicolons Control structures Functions

Outline

1 IntroductionExample

2 Formatting

3 Commentary

4 NamesPackage namesGettersInterface namesMixedCaps

5 Semicolons

6 Control structuresIfRedeclaration and reassignmentForSwitchType switch

7 FunctionsMultiple return valuesNamed result parametersDefer

Effective Go Jongseok Choi 2 / 31

Page 3: Golang

Introduction Formatting Commentary Names Semicolons Control structures Functions

Introduction

What is Go?

Although it borrows ideas from existing languages, it has unusual properties thatmake effective Go programs different in character from programs written in itsrelatives.

A straightforward translation of a C++ or Java program into Go is unlikely toproduce a satisfactory result.

In other words, to write Go well, it’s important to understand its properties andidioms.

Effective Go Jongseok Choi 3 / 31

Page 4: Golang

Introduction Formatting Commentary Names Semicolons Control structures Functions

Example

Example

The Go package sources1 are intended to serve not only as the core library but also asexamples of how to use the language.

1https://golang.org/src/

Effective Go Jongseok Choi 4 / 31

Page 5: Golang

Introduction Formatting Commentary Names Semicolons Control structures Functions

Formatting

Formatting issues are the most contentious but the least consequential.

With Go we take an unusual approach and let the machine take care of mostformatting issues.

The gofmt reads a Go program and emits the source in a standard style ofindentation and vertical alignment, retaining and if necessary reformattingcomments.

1 type T struct {2 name string // name of the object3 value int // its value4 }

Code 1: Unformatted Go code

1 type T struct {2 name string // name of the object3 value int // its value4 }

Code 2: Formatted Go code

Effective Go Jongseok Choi 5 / 31

Page 6: Golang

Introduction Formatting Commentary Names Semicolons Control structures Functions

Formatting

IndentationWe use tabs for indentation and gofmt emits them by default. Use spaces only if youmust.

Line lengthGo has no line length limit. Don’t worry about overflowing a punched card. If a linefeels too long, wrap it and indent with an extra tab.

ParenthesesGo needs fewer parentheses than C and Java: control structures (if, for, switch) do nothave parentheses in their syntax. Also, the operator precedence hierarchy is shorter andclearer, so

1 x<<8 + y<<16

Code 3: Operator precedence

Effective Go Jongseok Choi 6 / 31

Page 7: Golang

Introduction Formatting Commentary Names Semicolons Control structures Functions

Commentary

Comments style

C-style /* */ block

C++-style // line

The program godoc processes Go source files to extract documentation about the con-tents of the package.

For multi-file packages, the package comment only needs to be present in onefile, and any one will do.

1 /*2 Package regexp implements a simple library for regular expressions .34 The syntax of the regular expressions accepted is:56 regexp:7 concatenation { ’|’ concatenation }8 concatenation :9 { closure }

10 closure:11 term [ ’*’ | ’+’ | ’?’ ]12 term:13 ’^’14 ’$’15 ’.’16 character17 ’[’ [ ’^’ ] character -ranges ’]’18 ’(’ regexp ’)’19 */20 package regexp

Effective Go Jongseok Choi 7 / 31

Page 8: Golang

Introduction Formatting Commentary Names Semicolons Control structures Functions

Commentary

If the package is simple, the package comment can be brief.

Depending on the context, godoc might not even reformat comments, so makesure they look good straight up.

Inside a package, any comment immediately preceding a top-level declarationserves as a doc comment for that declaration.

The first sentence should be a one-sentence summary that starts with the namebeing declared.

1 // Package path implements utility routines for2 // manipulating slash - separated filename paths.

1 // Compile parses a regular expression and returns , if successful ,2 // a Regexp that can be used to match against text.3 func Compile(str string) (*Regexp , error) {

Effective Go Jongseok Choi 8 / 31

Page 9: Golang

Introduction Formatting Commentary Names Semicolons Control structures Functions

Commentary

Imagine you couldn’t remember the name “Compile” but were looking for the parsingfunction for regular expressions.

If all the doc comments in the package began, ”This function...”, grep wouldn’thelp you remember the name.

1 $ godoc regexp | grep parse2 Compile parses a regular expression and returns , if successful , a Regexp

parsed. It simplifies safe initialization of global variables holdingcannot be parsed. It simplifies safe initialization of global variables

Effective Go Jongseok Choi 9 / 31

Page 10: Golang

Introduction Formatting Commentary Names Semicolons Control structures Functions

Commentary

Go’s declaration syntax allows grouping of declarations.

A single doc comment can introduce a group of related constants or variables.

Grouping can also indicate relationships between items, such as the fact that aset of variables is protected by a mutex.

1 // Error codes returned by failures to parse an expression .2 var (3 ErrInternal = errors.New("regexp: internal error")4 ErrUnmatchedLpar = errors.New("regexp: unmatched ’(’")5 ErrUnmatchedRpar = errors.New("regexp: unmatched ’)’")6 ...7 )

1 import "sync"23 var (4 countLock sync.Mutex5 inputCount uint326 outputCount uint327 errorCount uint328 )

Effective Go Jongseok Choi 10 / 31

Page 11: Golang

Introduction Formatting Commentary Names Semicolons Control structures Functions

Package names

Package names

When a package is imported, the package name becomes an accessor for the contents.

By convention, packages are given lower case, single-word names.there should be no need for underscores or mixedCaps.

Another convention is that the package name is the base name of its sourcedirectory.

the package in src/encoding/base64 is imported as ”encoding/base64” but has namebase64.

1 import "encoding/base64"

Use the package structure to help you choose good names.

Another short example is once.Do.once.Do(setup) reads well and would not be improved by writingonce.DoOrWaitUntilDone(setup)

Long names don’t automatically make things more readable.

A helpful doc comment can often be more valuable than an extra long name.

Effective Go Jongseok Choi 11 / 31

Page 12: Golang

Introduction Formatting Commentary Names Semicolons Control structures Functions

Getters

Getters

Go doesn’t provide automatic support for getters and setters.

There’s nothing wrong with providing getters and setters yourself.

But it’s neither idiomatic nor necessary to put Get into the getter’s name.

If you have a field called owner (lower case, unexported).

The getter method should be called Owner (upper case, exported), not GetOwner.

A setter function, if needed, will likely be called SetOwner.

1 owner := obj.Owner ()2 if owner != user {3 obj.SetOwner(user)4 }

Effective Go Jongseok Choi 12 / 31

Page 13: Golang

Introduction Formatting Commentary Names Semicolons Control structures Functions

Interface names

Interface names

By convention, one-method interfaces are named by the method name plus an -ersuffix or similar modification to construct an agent noun

Reader, Writer, Formatter, CloseNotifier etc.

There are a number of such names and it is productive to honor them and the functionnames they capture.

To avoid confusion, do not give your method one of those names unless it has thesame signature and meaning.

If your type implements a method with the same meaning as a method on awell-known type.

Give it the same name and signature call your string-converter method String notToString.

Effective Go Jongseok Choi 13 / 31

Page 14: Golang

Introduction Formatting Commentary Names Semicolons Control structures Functions

MixedCaps

MixedCaps

Finally, the convention in Go is to use MixedCaps or mixedCaps rather thanunderscores to write multiword names.

Effective Go Jongseok Choi 14 / 31

Page 15: Golang

Introduction Formatting Commentary Names Semicolons Control structures Functions

Semicolons

Like C, Go’s formal grammar uses semicolons to terminate statements

But unlike in C, those semicolons do not appear in the source.

Instead the lexer uses a simple rule to insert semicolons automatically as it scans,so the input text is mostly free of them.

Semicolons insertion rules

if the newline comes after a token that could end a statement, insert a semicolon.

1 break continue fallthrough return ++ -- ) }

A semicolon can also be omitted immediately before a closing brace, so astatement such as for

1 go func() { for { dst <- <-src } }()

Effective Go Jongseok Choi 15 / 31

Page 16: Golang

Introduction Formatting Commentary Names Semicolons Control structures Functions

Semicolons

One consequence of the semicolon insertion rules is that you cannot put the openingbrace of a control structure (if, for, switch, or select) on the next line.

1 if i < f() {2 g()3 }

1 if i < f() // wrong!2 { // wrong!3 g()4 }

Effective Go Jongseok Choi 16 / 31

Page 17: Golang

Introduction Formatting Commentary Names Semicolons Control structures Functions

Control structures

The control structures of Go are related to those of C but differ in important ways.

There is no do or while loop, only a slightly generalized for.

if and switch accept an optional initialization statement like that of for/

break and continue statements take an optional label to identify what to breakor continue.

there are new control structures including a type switch and a multiwaycommunications multiplexer, select.

There are no parentheses and the bodies must always be brace-delimited.

Effective Go Jongseok Choi 17 / 31

Page 18: Golang

Introduction Formatting Commentary Names Semicolons Control structures Functions

If

If

In Go,

Mandatory braces.

if and switch accept an initialization statement.

The unnecessary else is omitted.

1 if x > 0 {2 return y3 }

1 if err := file.Chmod (0664); err != nil {2 log.Print(err)3 return err4 }

Effective Go Jongseok Choi 18 / 31

Page 19: Golang

Introduction Formatting Commentary Names Semicolons Control structures Functions

Redeclaration and reassignment

Redeclaration and reassignment

In a := declaration a variable v may appear even if it has already been declared,provided:

This declaration is in the same scope as the existing declaration of v (if v isalready declared in an outer scope, the declaration will create a new variable §)

The corresponding value in the initialization is assignable to v.

There is at least one other variable in the declaration that is being declared anew.

1 f, err := os.Open(name)2 d, err := f.Stat()

Effective Go Jongseok Choi 19 / 31

Page 20: Golang

Introduction Formatting Commentary Names Semicolons Control structures Functions

For

For

The Go for loop is similar to—but not the same as—C’s.

It unifies for and while and there is no do-while.

There are three forms, only one of which has semicolons.

1 // Like a C for2 for init; condition; post {3 }45 // Like a C while6 for condition {7 }89 // Like a C for (;;)

10 for {11 }

Effective Go Jongseok Choi 20 / 31

Page 21: Golang

Introduction Formatting Commentary Names Semicolons Control structures Functions

For

For

If you’re looping over an array, slice, string, or map, or reading from a channel, a rangeclause can manage the loop.

If you only need the first item in the range (the key or index), drop the second:“key := range m.”

If you only need the second item in the range (the value), use the blank identifier,an underscore, to discard the first: “ ,value := range m”

1 for key , value := range oldMap {2 newMap[key] = value3 }

Effective Go Jongseok Choi 21 / 31

Page 22: Golang

Introduction Formatting Commentary Names Semicolons Control structures Functions

For

For

Finally,

Go has no comma operator and ++ and – are statements not expressions.

if you want to run multiple variables in a for you should use parallel assignment.

1 // Reverse a2 for i, j := 0, len(a) -1; i < j; i, j = i+1, j-1 {3 a[i], a[j] = a[j], a[i]4 }

Effective Go Jongseok Choi 22 / 31

Page 23: Golang

Introduction Formatting Commentary Names Semicolons Control structures Functions

Switch

Switch

Go’s switch is more general than C’s.

The expressions need not be constants or even integers.

The cases are evaluated top to bottom until a match is found.

If the switch has no expression it switches on true.

It’s therefore possible to write an if-else-if-else chain as a switch.

1 func unhex(c byte) byte {2 switch {3 case ’0’ <= c && c <= ’9’:4 return c - ’0’5 case ’a’ <= c && c <= ’f’:6 return c - ’a’ + 107 case ’A’ <= c && c <= ’F’:8 return c - ’A’ + 109 }

10 return 011 }

Effective Go Jongseok Choi 23 / 31

Page 24: Golang

Introduction Formatting Commentary Names Semicolons Control structures Functions

Switch

Switch

There is no automatic fall through, but cases can be presented in comma-separatedlists.

1 func shouldEscape(c byte) bool {2 switch c {3 case ’ ’, ’?’, ’&’, ’=’, ’#’, ’+’, ’%’:4 return true5 }6 return false7 }

Effective Go Jongseok Choi 24 / 31

Page 25: Golang

Introduction Formatting Commentary Names Semicolons Control structures Functions

Switch

Switch

Loop escape

Go that can be accomplished by putting a label on the loop and “breaking” tothat label.

The continue statement also accepts an optional label but it applies only toloops.

1 Loop:2 for n := 0; n < len(src); n += size {3 switch {4 case src[n] < sizeOne:5 if validateOnly {6 break7 }8 size = 19 update(src[n])

1011 case src[n] < sizeTwo:12 if n+1 >= len(src) {13 err = errShortInput14 break Loop15 }16 if validateOnly {17 break18 }19 size = 220 update(src[n] + src[n+1]<<shift)21 }22 }

1 // Compare returns an integer comparing the two byte slices ,2 // lexicographically .3 // The result will be 0 if a == b, -1 if a < b, and +1 if a > b4 func Compare(a, b []byte) int {5 for i := 0; i < len(a) && i < len(b); i++ {6 switch {7 case a[i] > b[i]:8 return 19 case a[i] < b[i]:

10 return -111 }12 }13 switch {14 case len(a) > len(b):15 return 116 case len(a) < len(b):17 return -118 }19 return 020 }

Code 4: Using slice in switch

Effective Go Jongseok Choi 25 / 31

Page 26: Golang

Introduction Formatting Commentary Names Semicolons Control structures Functions

Type switch

Type switch

A switch can also be used to discover the dynamic type of an interface variable.

Such a type switch uses the syntax of a type assertion with the keyword type

inside the parentheses.

1 var t interface {}2 t = functionOfSomeType ()3 switch t := t.(type) {4 default:5 fmt.Printf("unexpected type %T\n", t) // %T prints whatever type t

has6 case bool:7 fmt.Printf("boolean %t\n", t) // t has type bool8 case int:9 fmt.Printf("integer %d\n", t) // t has type int

10 case *bool:11 fmt.Printf("pointer to boolean %t\n", *t) // t has type *bool12 case *int:13 fmt.Printf("pointer to integer %d\n", *t) // t has type *int14 }

Effective Go Jongseok Choi 26 / 31

Page 27: Golang

Introduction Formatting Commentary Names Semicolons Control structures Functions

Multiple return values

Multiple return values

One of Go’s unusual features is that functions and methods can return multiplevalues.

This form can be used to improve on a couple of clumsy idioms in C programs.in-band error returns such as -1 for EOF and modifying an argument passed by address.

1 func (file *File) Write(b []byte) (n int , err error)

1 func nextInt(b []byte , i int) (int , int) {2 for ; i < len(b) && !isDigit(b[i]); i++ {3 }4 x := 05 for ; i < len(b) && isDigit(b[i]); i++ {6 x = x*10 + int(b[i]) - ’0’7 }8 return x, i9 }

Effective Go Jongseok Choi 27 / 31

Page 28: Golang

Introduction Formatting Commentary Names Semicolons Control structures Functions

Named result parameters

Named result parameters

The return or result “parameters” of a Go function can be given names and used asregular variables, just like the incoming parameters.

When named, they are initialized to the zero values for their types when thefunction begins.

1 func ReadFull(r Reader , buf []byte) (n int , err error) {2 for len(buf) > 0 && err == nil {3 var nr int4 nr, err = r.Read(buf)5 n += nr6 buf = buf[nr:]7 }8 return9 }

Effective Go Jongseok Choi 28 / 31

Page 29: Golang

Introduction Formatting Commentary Names Semicolons Control structures Functions

Defer

Defer

Go’s defer statement schedules a function call (the deferred function) to be runimmediately before the function executing the defer returns.

It’s an unusual but effective way to deal with situations such as resources thatmust be released regardless of which path a function takes to return.

Deferring a call to a function such as Close has two advantages.

First, it guarantees that you will never forget to close the file.

Second, it means that the close sits near the open.

1 // Contents returns the file ’s contents as a string.2 func Contents(filename string) (string , error) {3 f, err := os.Open(filename)4 if err != nil {5 return "", err6 }7 defer f.Close() // f.Close will run when we’re finished.89 var result []byte

10 buf := make ([]byte , 100)11 for {12 n, err := f.Read(buf [0:])13 result = append(result , buf[0:n]...) // append is discussed

later.14 if err != nil {15 if err == io.EOF {16 break17 }18 return "", err // f will be closed if we return here

.19 }20 }21 return string(result), nil // f will be closed if we return here.22 }

Effective Go Jongseok Choi 29 / 31

Page 30: Golang

Introduction Formatting Commentary Names Semicolons Control structures Functions

Defer

Defer

The arguments to the deferred function are evaluated when the defer executes, notwhen the call executes.

Deferred functions are executed in LIFO order.

1 for i := 0; i < 5; i++ {2 defer fmt.Printf("%d ", i)3 }

A more plausible example is a simple way to trace function execution through theprogram.

1 func trace(s string) { fmt.Println("entering:", s) }2 func untrace(s string) { fmt.Println("leaving:", s) }34 // Use them like this:5 func a() {6 trace("a")7 defer untrace("a")8 // do something ....9 }

Effective Go Jongseok Choi 30 / 31

Page 31: Golang

Introduction Formatting Commentary Names Semicolons Control structures Functions

Defer

Defer

We can do better by exploiting the fact that arguments to deferred functions areevaluated when the defer executes.

1 func trace(s string) string {2 fmt.Println("entering:", s)3 return s4 }56 func un(s string) {7 fmt.Println("leaving:", s)8 }9

10 func a() {11 defer un(trace("a"))12 fmt.Println("in a")13 }1415 func b() {16 defer un(trace("b"))17 fmt.Println("in b")18 a()19 }2021 func main() {22 b()23 }

Result

e n t e r i n g : bi n be n t e r i n g : ai n al e a v i n g : al e a v i n g : b

Effective Go Jongseok Choi 31 / 31

Page 32: Golang

Introduction Formatting Commentary Names Semicolons Control structures Functions

Defer

Google.Effective go, Mar. 2017.

Effective Go Jongseok Choi 31 / 31