Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Философия Go

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on. →

Философия Go

Постулаты Go (Go proverbs), их применение на практике

Avatar for Igor Zibarev

Igor Zibarev

October 28, 2017

More Decks by Igor Zibarev

Other Decks in Technology

Transcript

  1. GO

  2. func PrintJSON(v interface{}) error { b, err := json.Marshal(v) if

    err != nil { return err } fmt.Println(string(b)) return nil }
  3. func PrintJSON(m json.Marshaler) error { b, err := m.MarshalJSON() if

    err != nil { return err } fmt.Println(string(b)) return nil }
  4. Иногда interface{} необходим func Primitive(val string, typ string) (value interface{},

    err error) { switch typ { case "string": return convertString(val) case "number": return convertNumber(val) case "integer": return convertInteger(val) case "boolean": return convertBoolean(val) default: return nil, fmt.Errorf( "unknown type: %s", typ, ) }
  5. Clear func Clear(s string) string { words := make([]string, len(s))

    for i, c := range s { char := strings.ToLower(string(c)) word := strings.Repeat(char, i+1) words[i] = strings.Title(word) } return strings.Join(words, "-") }
  6. Clever func Clever(s string) string { var bs []byte for

    i, b := range []byte(s) { if i > 0 { bs = append(bs, '-') } u, l := b, b if b >= 'a' && b <= 'z' { u -= 32 } else { l += 32 } bs = append(bs, u) for j := 0; j < i; j ++ { bs = append(bs, l) } } return string(bs)
  7. // GET /api/v1/shirts?color=white&limit=10&offset=20 type Params struct { Color string `schema:"color"`

    Limit int `schema:"limit"` Offset int `schema:"offset"` } var p Params schema.NewDecoder().Decode(&p, req.URL.Query()) Пример: теги структур
  8. // Get the field walking the struct fields by index.

    for _, name := range parts[0].path { if v.Type().Kind() == reflect.Ptr { if v.IsNil() { v.Set(reflect.New(v.Type().Elem())) } v = v.Elem() } v = v.FieldByName(name) } // Don't even bother for unexported fields. if !v.CanSet() { return nil } // Dereference if needed. t := v.Type() if t.Kind() == reflect.Ptr { t = t.Elem() if v.IsNil() { v.Set(reflect.New(t)) github.com/gorilla/schema
  9. type MyInt struct { mu sync.Mutex val int } func

    main() { var i MyInt i.mu.Lock() i.val ++ i.mu.Unlock() } sync.Mutex
  10. Методы и nil type Config struct { path string }

    func (c *Config) Path() string { if c == nil { return "/usr/home" } return c.path } func main() { var c1 *Config var c2 = &Config{ path: "/export", } fmt.Println(c1.Path(), c2.Path()) // вывод: /usr/home /export }
  11. type stackTracer interface { StackTrace() StackTrace } if err, ok

    := err.(stackTracer); ok { for _, f := range err.StackTrace() { fmt.Printf("%+s:%d", f) } } Ошибки реализуют интерфейсы
  12. “Returning error values is the worst form of error handling,

    except all the others that have been tried.”
  13. func (db *DB) QueryRow(query string, args ...interface{}) *Row { rows,

    err := db.Query(ctx, query, args ...) return &Row{rows: rows, err: err} } func (r *Row) Scan(dest ...interface{}) error { if r.err != nil { return r.err } // ... } database/sql
  14. package main import ( "fmt" "time" ) func say(s string)

    { for i := 0; i < 5; i ++ { time.Sleep(time.Second) fmt.Println(s) } } func main() { go say("world") // create a new goroutine say("hello") // current goroutine time.Sleep(time.Second) }
  15. var counter int func main() { go incrementor("Foo:") go incrementor("Bar:")

    time.Sleep(time.Second * 2) fmt.Println("Final Counter:", counter) } func incrementor(s string) { rand.Seed(time.Now().UnixNano()) for i := 0; i < 10; i ++ { x := counter x ++ time.Sleep(time.Duration(rand.Intn(3)) * time.Millisecond) counter = x fmt.Println(s, i, "Counter:", counter) } }
  16. Bar: 0 Counter: 1 Bar: 1 Counter: 2 Foo: 0

    Counter: 1 Bar: 2 Counter: 3 Foo: 1 Counter: 2 Bar: 3 Counter: 4 Bar: 4 Counter: 5 Foo: 2 Counter: 3 Foo: 3 Counter: 4 Bar: 5 Counter: 6 Foo: 4 Counter: 7 Foo: 5 Counter: 8 Bar: 6 Counter: 7 Bar: 7 Counter: 8 Bar: 8 Counter: 9 Foo: 6 Counter: 9 Foo: 7 Counter: 10 Bar: 9 Counter: 10 Foo: 8 Counter: 11 Foo: 9 Counter: 12 Final Counter: 12
  17. “Concurrency is the composition of independently executing processes, while parallelism

    is the simultaneous execution of (possibly related) computations.”
  18. Concurrency is about dealing with lots of things at once.

    Parallelism is about doing lots of things at once.
  19. func main() { c := make(chan int) go func() {

    for i := 0; i < 10; i ++ { c <- i } }() go func() { for { fmt.Println( <-c) } }() time.Sleep(time.Second) } Channels
  20. var ( counter int mutex sync.Mutex ) func main() {

    go incrementor("Foo:") go incrementor("Bar:") time.Sleep(time.Second * 2) fmt.Println("Final Counter:", counter) } func incrementor(s string) { for i := 0; i < 20; i ++ { time.Sleep(time.Duration(rand.Intn(20)) * time.Millisecond) mutex.Lock() counter ++ fmt.Println(s, i, "Counter:", counter) mutex.Unlock() } }
  21. func incrementor(s string) chan int { out := make(chan int)

    go func() { for i := 0; i < 20; i ++ { out <- 1 fmt.Println(s, i) } close(out) }() return out } Создаем incrementor
  22. func puller(c chan int) chan int { out := make(chan

    int) go func() { var sum int for n := range c { sum += n } out <- sum close(out) }() return out } Создаем puller
  23. func main() { c1 := incrementor("Foo:") c2 := incrementor(“Bar:") c3

    := puller(c1) c4 := puller(c2) fmt.Println("Final Counter:", <-c3+ <-c4) } Main
  24. output Foo: 0 Foo: 1 Foo: 2 Foo: 3 Foo:

    4 Foo: 5 Foo: 6 Foo: 7 Foo: 8 Bar: 0 Bar: 1 Bar: 2 Foo: 9 Foo: 10 Bar: 3 Foo: 11 Foo: 12 Bar: 4 Bar: 5 Foo: 13 Bar: 6 Bar: 7 Foo: 14 Bar: 8 Bar: 9 Bar: 10 Bar: 11 Bar: 12 Bar: 13 Foo: 15 Bar: 14 Bar: 15 Bar: 16 Bar: 17 Bar: 18 Bar: 19 Foo: 16 Foo: 17 Foo: 18 Foo: 19 Final Counter: 40
  25. os.OpenFile var r int for { var e error r,

    e = syscall.Open(name, flag|syscall.O_CLOEXEC, syscallMode(perm)) if e == nil { break } // On OS X, sigaction(2) doesn't guarantee that SA_RESTART will cause // open(2) to be restarted for regular files. This is easy to reproduce on // fuse file systems (see http: //golang.org/issue/11180). if runtime.GOOS == "darwin" && e == syscall.EINTR { continue } return nil, &PathError{"open", name, e} }
  26. Build tags // +build darwin dragonfly freebsd netbsd openbsd solaris

    package os // According to sticky(8), neither open(2) nor mkdir(2) will create // a file with the sticky bit set. const supportsCreateWithStickyBit = false
  27. package rand /* #include <stdlib.h> */ import "C" func Random()

    int { return int(C.random()) } func Seed(i int) { C.srandom(C.uint(i)) }
  28. import "C" import "unsafe" // ... var cArr *C.YourType =

    C.getTheArray() length := C.getTheArrayLength() slice := (*[1 << 30]C.YourType)(unsafe.Pointer(cArr))[:length:length]
  29. a := [4]int{0, 1, 2, 3} p1 := unsafe.Pointer(&a[1]) p3

    := unsafe.Pointer(uintptr(p1) + 2 * unsafe.Sizeof(a[0])) *(*int)(p3) = 6 fmt.Println("a =", a) // a = [0 1 2 6]
  30. // Copied from sync.Once but we don't want // to

    cache the results if there is an error type cacheOnce struct { m sync.Mutex done uint32 } // Copied from sync.Once but we don't want // to cache the results if there is an error func (o *cacheOnce) cache(f func() error) { if atomic.LoadUint32(&o.done) == 1 { return } // ... github.com/kubernetes/kubernetes/pkg/volume/ metrics_cached.go
  31. func testSend(t *testing.T, newTransport func() vice.Transport) { is := is.New(t)

    transport := newTransport() select { case transport.Send("something") <- []byte("message"): return case <-time.After(1 * time.Second): is.Fail("send channels shouldn't block") } } github.com/matryer/vice/vicetest (тестирует github.com/matryer/vice)
  32. // Exit causes the current program to exit // with

    the given status code. Conventionally, // code zero indicates success, non-zero an error. // The program terminates immediately; deferred // functions are not run. func Exit(code int) { // ... } Документация к API
  33. Документация к реализации if res.primary && fallbackTimer.Stop() { // If

    we were able to stop the timer, that means it // was running (hadn't yet started the fallback), but // we just got an error on the primary path, so start // the fallback immediately (in 0 nanoseconds). fallbackTimer.Reset(0) }
  34. var user = os.Getenv("USER") func init() { if user ==

    "" { panic("no value for $USER") } } Допустимая паника
  35. switch direction { case "left": person.GoLeft() case "right": person.GoRight() default:

    panic("unknown direction") } Лучше было бы вернуть ошибку