The State of Go
Where we are in February 2016
Francesc Campoy
Gopher at Google
Francesc Campoy
Gopher at Google
Go 1.4 is one year old (happy birthday!)
Go 1.5 is already 6 months old!
Go 1.6 to be released sometime in February.
Go 1.6 Candidate Release 1 was released on January 28th
2The slides are available on go.dev/talks/2016/state-of-go.slide
Most of the code examples won't run except locally and using Go 1.6.
The playground still runs Go 1.5.
3Changes since Go 1.5:
None.
This is a feature.
6A couple of new things, in order of excitement.
Also more speed and fewer bugs.
8If:
you're using HTTP/2!
9At a high level, HTTP/2:
Imagine that given a slice of strings:
[]string{"one", "two", "three"}
We want to write a template that will generate:
<ul> <li>one</li> <li>two</li> <li>three</li> </ul>
What template would you write?
11Naturally, I write this:
// +build ignore,OMIT
package main
import (
"html/template"
"log"
"os"
)
var tmpl = template.Must(template.New("tmpl").Parse(` <ul> {{range .}} <li>{{.}}</li> {{end}} </ul> `))
func main() {
err := tmpl.Execute(os.Stdout, []string{"one", "two", "three"})
if err != nil {
log.Fatal(err)
}
}
But unfortunately it's not exactly what I want!
12We need to be careful with the line breaks.
// +build ignore,OMIT
package main
import (
"html/template"
"log"
"os"
)
var tmpl = template.Must(template.New("tmpl").Parse(` <ul> {{range .}}<li>{{.}}</li> {{end}}</ul> `))
func main() {
err := tmpl.Execute(os.Stdout, []string{"one", "two", "three"})
if err != nil {
log.Fatal(err)
}
}
This works now, but ... I don't really like my code!
13Go 1.6 brings two new delimiters:
{{-
-}}
Similar to {{
and }}
, but all white space on the -
side will be trimmed.
The template:
{{23 -}} < {{- 45}}
generates:
23<45
We can now have:
// +build ignore,OMIT
package main
import (
"html/template"
"log"
"os"
)
var tmpl = template.Must(template.New("tmpl").Parse(` <ul> {{range . -}} <li>{{.}}</li> {{end -}} </ul> `))
func main() {
err := tmpl.Execute(os.Stdout, []string{"one", "two", "three"})
if err != nil {
log.Fatal(err)
}
}
Go 1.6 brings also a new action named block
.
Let's see what it is useful for.
16
Both <ul>
share the same structure.
{{define "presentation"}} Authors: <ul> {{range .Authors}} <li>{{.}}</li> {{end}} </ul> Topics: <ul> {{range .Topics}} <li>{{.}}</li> {{end}} </ul> {{end}}
Templates can be used to avoid repetition.
17We can define a new template:
{{define "list"}} <ul> {{range .}} <li>{{.}}</li> {{end}} </ul> {{end}}
And use it where needed:
{{define "presentation"}} Authors: {{template "list" .Authors}} Topics: {{template "list" .Topics}} {{end}}
We can parse that template and execute it.
// +build ignore,OMIT
package main
import (
"html/template"
"log"
"os"
)
const tmplText = `
{{define "list"}}
<ul>
{{range .}}
<li>{{.}}</li>
{{end}}
</ul>
{{end}}
{{define "presentation"}}
Authors:
{{template "list" .Authors}}
Topics:
{{template "list" .Topics}}
{{end}}
`
type Presentation struct {
Authors []string
Topics []string
}
func main() { p := Presentation{ Authors: []string{"one", "two", "three"}, Topics: []string{"go", "templates"}, } tmpl := template.Must(template.New("presentation").Parse(tmplText)) err := tmpl.Execute(os.Stdout, p) if err != nil { log.Fatal(err) } }
We made also our template easier to reuse, as we can redefine list
.
// +build ignore,OMIT
package main
import (
"html/template"
"log"
"os"
"strings"
)
const tmplText = `
{{define "list"}}
<ul>
{{range .}}
<li>{{.}}</li>
{{end}}
</ul>
{{end}}
{{define "presentation"}}
Authors:
{{template "list" .Authors}}
Topics:
{{template "list" .Topics}}
{{end}}
`
type Presentation struct {
Authors []string
Topics []string
}
func main() { p := Presentation{ Authors: []string{"one", "two", "three"}, Topics: []string{"go", "templates"}, } tmpl := template.Must(template.New("presentation").Parse(tmplText)) tmpl = tmpl.Funcs(template.FuncMap{"join": strings.Join}) tmpl = template.Must(tmpl.Parse(`{{define "list"}} {{join . " | "}} {{ end}}`)) err := tmpl.Execute(os.Stdout, p) if err != nil { log.Fatal(err) } }
The block
action defines and executes a template in place.
{{define "presentation"}} Authors: {{block "list" .Authors}} <ul> {{- range .}} <li>{{.}}</li> {{- end}} </ul> {{end}} Topics: {{template "list" .Topics}} {{end}}
That template defined by block
can be:
define
.It is more compact when
We can make the following template more compact with block
.
{{define "content" .}} <h1>{{.Heading}}<h1> <p>{{.Content}}</p> {{end}} {{define "page"}} <title>{{.Title}}</title> <body> {{template "content" .}} </body> {{end}}
We can make the following template more compact with block
.
{{define "page"}} <title>{{.Title}}</title> <body> {{block "content" .}} <h1>{{.Heading}}<h1> <p>{{.Content}}</p> {{end}} </body> {{end}}
And still easily redefine content
.
Sort
sorts your data by calling Less
, Swap
, and Len
.
We reduced the number of comparisons and swaps by about 10%.
Sort []int
with Go 1.5
BenchmarkSort_1-4 20000000 67.2 ns/op BenchmarkSort_10-4 10000000 227 ns/op BenchmarkSort_100-4 500000 3863 ns/op BenchmarkSort_1000-4 30000 52189 ns/op
Sort []int
with Go 1.6
BenchmarkSort_1-4 20000000 64.7 ns/op BenchmarkSort_10-4 10000000 137 ns/op BenchmarkSort_100-4 500000 2849 ns/op BenchmarkSort_1000-4 30000 46949 ns/op
Reminder: sort.Sort is not a stable sort.
// +build ignore,OMIT
package main
import (
"fmt"
"sort"
"strings"
)
type byLength []string func (b byLength) Len() int { return len(b) } func (b byLength) Less(i, j int) bool { return len(b[i]) < len(b[j]) } func (b byLength) Swap(i, j int) { b[i], b[j] = b[j], b[i] } func main() { values := []string{"ball", "hell", "one", "joke", "fool", "moon", "two"} sort.Sort(byLength(values)) fmt.Println(strings.Join(values, "\n")) }
Use sort.Stable
:
// +build ignore,OMIT
package main
import (
"fmt"
"sort"
"strings"
)
type byLength []string
func (b byLength) Len() int { return len(b) }
func (b byLength) Less(i, j int) bool { return len(b[i]) < len(b[j]) }
func (b byLength) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
func main() { values := []string{"ball", "hell", "one", "joke", "fool", "moon", "two"} sort.Stable(byLength(values)) fmt.Println(strings.Join(values, "\n")) }
time.Parse
is smarter!
// +build ignore,OMIT
package main
import (
"fmt"
"time"
)
func main() { days := []string{"2015 Feb 29", "2016 Feb 29", "2017 Feb 29"} fmt.Println("Are these days valid?") for _, day := range days { _, err := time.Parse("2006 Jan 2", day) fmt.Printf("%v -> %v\n", day, err == nil) } }
Detection of unsafe concurrent access to maps.
// +build ignore,OMIT
package main
import (
"fmt"
"sync"
)
func main() {
const workers = 100 // what if we have 1, 2, 25? var wg sync.WaitGroup wg.Add(workers) m := map[int]int{} for i := 1; i <= workers; i++ { go func(i int) { for j := 0; j < i; j++ { m[i]++ } wg.Done() }(i) } wg.Wait()
fmt.Println(m)
}
Outputs:
fatal error: concurrent map read and map write fatal error: concurrent map writes
No!
Let's benchmark it - with a correct solution.
func count(n int) { var wg sync.WaitGroup wg.Add(n) m := map[int]int{} var mu sync.Mutex for i := 1; i <= n; i++ { go func(i int) { for j := 0; j < i; j++ { mu.Lock() m[i]++ mu.Unlock() } wg.Done() }(i) } wg.Wait() }
Go 1.4 - GOMAXPROCS = 4
BenchmarkCount_1 1000000 1862 ns/op BenchmarkCount_10 100000 21214 ns/op BenchmarkCount_100 1000 1602507 ns/op BenchmarkCount_1000 10 141712948 ns/op
Go 1.5 - GOMAXPROCS = 4
BenchmarkCount_1-4 2000000 867 ns/op BenchmarkCount_10-4 200000 6909 ns/op BenchmarkCount_100-4 1000 1025092 ns/op BenchmarkCount_1000-4 20 94093719 ns/op
Go 1.6 - GOMAXPROCS = 4
BenchmarkCount_1-4 2000000 750 ns/op BenchmarkCount_10-4 200000 6582 ns/op BenchmarkCount_100-4 2000 1113790 ns/op BenchmarkCount_1000-4 20 87998054 ns/op
Go 1.4 - GOMAXPROCS = 1
BenchmarkCount_1 100000 1370 ns/op BenchmarkCount_10 20000 8622 ns/op BenchmarkCount_100 500 362725 ns/op BenchmarkCount_1000 50 31378803 ns/op
Go 1.5 - GOMAXPROCS = 1
BenchmarkCount_1-4 2000000 776 ns/op BenchmarkCount_10-4 200000 6288 ns/op BenchmarkCount_100-4 3000 345037 ns/op BenchmarkCount_1000-4 50 31751625 ns/op
Go 1.6 - GOMAXPROCS = 1
BenchmarkCount_1-4 2000000 767 ns/op BenchmarkCount_10-4 200000 6041 ns/op BenchmarkCount_100-4 5000 329328 ns/op BenchmarkCount_1000-4 50 30176034 ns/op
At GopherCon 2015 Rick Hudson gave a presentation about the Go 1.5 low latency collector
At QCon SF in November Rick Hudson gave an updated presentation which showed this comparison of Go 1.5 to the upcoming Go 1.6
Yes, that is gigabytes on the X axis
37Right now it's even better!
Experimental ports to Linux on 64-bit MIPS (linux/mips64 and linux/mips64le).
Experimental port to Android on 32-bit x86 (android/386).
On Linux on little-endian 64-bit PowerPC (linux/ppc64le), Go 1.6 now supports cgo with external linking and is roughly feature complete.
On NaCl, Go 1.5 required SDK version pepper-41. Go 1.6 adds support for later SDK versions.
42Go is garbage collected, can C and Go share memory?
In short:
In more detail:
cgo
docs.This is checked by the runtime at execution.
You could disable the checks, but you probably shouldn't.
44package main /* int fn(void* arg) { return arg == 0; } */ import "C" import "unsafe" type T struct{ a, b int } type X struct{ t *T } func main() { t := T{a: 1, b: 2} C.fn(unsafe.Pointer(&t)) // correct x := X{t: &t} C.fn(unsafe.Pointer(&x)) // incorrect }
Outputs:
panic: runtime error: cgo argument has Go pointer to Go pointer
GO15VENDOREXPERIMENT is now enabled by default.
How does it work?
/home/user/gocode/ src/ server-one/ main.go (import "github.com/gorilla/mux") server-two/ main.go (import "github.com/gorilla/mux") vendor/ github.com/ gorilla/ mux/ ...
server-one
uses the mux
package in $GOPATH/src/github.com/gorilla/mux
.
server-two
uses the mux
package in vendor
.
Go 1.5 added the possibility of searching by name
go doc math Pi
Go 1.6 defines priority of packages with import paths with less elements.
Non vendored packages appear first.
48Go vet warns if the code prints a function instead of its result.
package main import "fmt" func foo() string { return "bar" } func main() { fmt.Printf("%v", foo) }
go vet
output:
main.go:8: arg foo in Println call is a function value, not a function call
The warning can be removed using %p
in the format string.
Code of Conduct announced on November 24th 2015
Go meetups:
Women Who Go - 7 chapters already!
51Go 1.6 ships soon!
Go meetups are organising to hold a release party on the 17th of February.