What's new in Go 1.1
Andrew Gerrand
Gopher
Andrew Gerrand
Gopher
Not finished yet. Monday maybe?
2Integer division by constant zero is now a compile-time error:
// +build ignore,OMIT
package main
func f(x int) int { return x / 0 }
func main() {
f(1)
}
Byte order marks are now permitted as the first character of a Go source file.
The misuse of "surrogate halves" is now caught by the compiler, libraries, and run-time.
If you don't know what this means, then it likely doesn't matter to you.
5Sometimes you want to turn a method into a plain function (binding it to its receiver). This is often referred to as "currying".
To do this under Go 1.0, you would use a closure:
// +build ignore,OMIT
package main
import "os"
func main() {
var w func([]byte) (int, error) w = func(b []byte) (int, error) { return os.Stdout.Write(b) } w([]byte("hello!\n"))
}
Go 1.1 now implements method values, so you can achieve the same thing by simply taking the method as a value:
// +build ignore,OMIT
package main
import "os"
func main() {
var w func([]byte) (int, error) w = os.Stdout.Write w([]byte("hello!\n"))
}
Before Go 1.1, a function that returned a value needed an explicit return
or call to panic
at the end of the function.
func slurp(r io.Reader) error { b := make([]byte, 1024) for { _, err := r.Read(b) if err != nil { if err == io.EOF { return nil } return err } } panic("unreachable") }
func min(a, b int) int { if a < b { return a } return b }
In Go 1.1, the rule about final "return" statements is more permissive.
func slurp(r io.Reader) error { b := make([]byte, 1024) for { _, err := r.Read(b) if err != nil { if err == io.EOF { return nil } return err } } }
func min(a, b int) int { if a < b { return a } else { return b } }
Under Go 1.0, int
and uint
were 32 bits wide on all systems.
With Go 1.1, both the gc
and gccgo
implementations now make int
and uint
64 bits on 64-bit platforms such as AMD64/x86-64.
Among other things, this enables the allocation of slices with more than 2 billion elements on 64-bit platforms.
10On 64-bit architectures, the maximum heap size has been enlarged substantially, from a few gigabytes to several tens of gigabytes. (The exact details depend on the system and may change.)
On 32-bit architectures, the heap size has not changed.
11
A major addition to the tools is a race detector, a way to find bugs in concurrent programs. To enable it, set the -race
flag when building or testing your program.
package main func main() { var a int go func() { for { if a == 0 { a = 1 } } }() for { if a == 1 { a = 0 } } }
For now, it is only available on 64-bit Linux, OS X, and Windows systems.
12The go command now gives better error messages:
$ go build foo/quxx can't load package: package foo/quxx: cannot find package "foo/quxx" in any of: /home/you/go/src/pkg/foo/quxx (from $GOROOT) /home/you/src/foo/quxx (from $GOPATH)
To help users better understand workspaces and GOPATH
, the go get
command will fail if GOPATH
is not set:
$ GOPATH= go get code.google.com/p/foo/quxx package code.google.com/p/foo/quxx: cannot download, $GOPATH not set. For more details see: go help gopath
The go get
command will also fail if GOPATH
and GOROOT
have the same value:
$ GOPATH=$GOROOT go get code.google.com/p/foo/quxx warning: GOPATH set to GOROOT (/home/you/go) has no effect package code.google.com/p/foo/quxx: cannot download, $GOPATH must not be set to $GOROOT. For more details see: go help gopath
The go test
command no longer deletes the binary when run with profiling enabled, to make it easier to analyze the profile. After running
$ go test -cpuprofile cpuprof.out mypackage
the file mypackage.test
will be left around for analysis.
The go test
command can now generate profiling information that reports where goroutines are blocked, enabled with the -blockprofile
option. The information is presented as a blocking profile.
The "go1.1" tag has been added to the list of default build constraints.
To build a file only with Go 1.1 and above, add this build constraint:
// +build go1.1
To build a file only with Go 1.0.x, use the converse constraint:
// +build !go1.1
This permits packages to take advantage of the new features in Go 1.1 while remaining compatible with earlier versions of Go.
16
The Go 1.1 tool chain adds experimental support for freebsd/arm
, netbsd/386
, netbsd/amd64
, netbsd/arm
, openbsd/386
and openbsd/amd64
platforms.
An ARMv6 or later processor is required for freebsd/arm
or netbsd/arm
.
Go 1.1 adds experimental support for cgo
on linux/arm
.
The old way:
r := bufio.NewReader(strings.NewReader(blob)) for { s, err := r.ReadString('\n') if err != nil { if err == io.EOF { break } log.Fatal(err) } fmt.Println(s) }
The new way:
// +build ignore,OMIT
package main
import (
"bufio"
"fmt"
"io"
"log"
"strings"
)
const blob = `Hey there,
fellow gophers!
Have a good day.
`
func old() {
// STARTold OMIT
r := bufio.NewReader(strings.NewReader(blob))
for {
s, err := r.ReadString('\n')
if err != nil {
if err == io.EOF {
break
}
log.Fatal(err)
}
fmt.Println(s)
}
// STOP OMIT
}
func main() {
s := bufio.NewScanner(strings.NewReader(blob)) for s.Scan() { fmt.Println(s.Text()) } if err := s.Err(); err != nil { log.Fatal(err) }
}
Custom split functions:
type SplitFunc func(data []byte, atEOF bool) (advance int, token []byte, err error)
For example, counting words:
// +build ignore,OMIT
package main
import (
"bufio"
"fmt"
"log"
"strings"
)
func main() {
const input = "Now is the winter of our discontent..." scanner := bufio.NewScanner(strings.NewReader(input)) scanner.Split(bufio.ScanWords) count := 0 for scanner.Scan() { count++ } if err := scanner.Err(); err != nil { log.Fatal(err) } fmt.Println(count)
}
The new functions ChanOf
, MapOf
and SliceOf
construct new types from existing types, for example to construct the type chan T
given only T
.
// +build ignore,OMIT
package main
import (
"fmt"
"reflect"
)
func sendSlice(slice interface{}) (channel interface{}) { sliceValue := reflect.ValueOf(slice) chanType := reflect.ChanOf(reflect.BothDir, sliceValue.Type().Elem()) chanValue := reflect.MakeChan(chanType, 0) go func() { for i := 0; i < sliceValue.Len(); i++ { chanValue.Send(sliceValue.Index(i)) } chanValue.Close() }() return chanValue.Interface() } func main() { ch := sendSlice([]int{1, 2, 3, 4, 5}).(chan int) for v := range ch { fmt.Println(v) } }
The new function MakeFunc
creates a wrapper function to make it easier to call a function with existing Values
.
// +build ignore,OMIT
package main
import (
"fmt"
"reflect"
)
func makeSwap(fptr interface{}) { swap := func(in []reflect.Value) []reflect.Value { return []reflect.Value{in[1], in[0]} } fn := reflect.ValueOf(fptr).Elem() v := reflect.MakeFunc(fn.Type(), swap) fn.Set(v) } func main() { var fn func(int, int) (int, int) makeSwap(&fn) fmt.Println(fn(0, 1)) }
On FreeBSD, Linux, NetBSD, OS X and OpenBSD, previous versions of the time
package returned times with microsecond precision. Go 1.1 now provides nanosecond precision on these systems.
The new method on time.Time
, YearDay
, provides the one-indexed day number of the year.
// +build ignore,OMIT
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println("Today is day", time.Now().YearDay())
}
The Timer
type has a new method Reset
that modifies the timer to expire after a specified duration. This helps to avoid unnecessary repeated Timer
allocations.
// +build ignore,OMIT
package main
import (
"fmt"
"math/rand"
"time"
)
func init() {
rand.Seed(10)
}
func sendMessages() chan string {
ch := make(chan string)
go func() {
for i := 0; ; i++ {
time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
ch <- fmt.Sprintf("message %v", i)
}
}()
return ch
}
func main() { timeout := time.NewTimer(80 * time.Millisecond) ch := sendMessages() for { select { case msg := <-ch: fmt.Println(msg) timeout.Reset(80 * time.Millisecond) case <-timeout.C: fmt.Println("timeout") return } } }
The new function ParseInLocation
parses the time in the context of a time zone, ignoring time zone information in the parsed string.
This function addresses a common source of confusion in the time API.
26
TrimPrefix
and TrimSuffix
functions have been added to the bytes
and strings
packages.
Code under Go 1.0 like this:
s := "Please pass the salt" if p := "Please "; strings.HasPrefix(s, p) { s = s[len(p):] }
May now be rewritten as:
s := "Please pass the salt" s = strings.TrimPrefix(s, "Please ")
The exp and old source subtrees, which are not included in binary distributions, have been moved to the new go.exp
sub-repository at golang.org/x/exp
.
To access the ssa
package, for example, run
$ go get golang.org/x/exp/ssa
and then in Go source,
import "golang.org/x/exp/ssa"
The old package exp/norm
has also been moved, but to a new repository go.text
, where the Unicode APIs and other text-related packages will be developed.
Code compiled with the Go 1.1 gc tool suite should be noticeably better for most Go programs.
Improvements relative to Go 1.0 seem to be about 30%-40%, sometimes much more, but occasionally less or even non-existent.
Major changes include: