blob: 4ec3f885ffe4ba00458ace1c9c0e75b5314d76a3 [file] [log] [blame]
10 things you (probably) don't know about Go
Andrew Gerrand
Gopher
https://plus.google.com/106356964679457436995
@enneff
http://golang.org
* 1. Anonymous structs
- Grouped globals
var config struct {
APIKey string
OAuthConfig oauth.Config
}
config.APIKey = "BADC0C0A"
- Template data
data := struct {
Title string
Users []*User
}{
title,
users,
}
err := tmpl.Execute(w, data)
(Cheaper and safer than using `map[string]interface{}`.)
* 1b. Anonymous structs
- Test tables
var indexRuneTests = []struct {
s string
rune rune
out int
}{
{"a A x", 'A', 2},
{"some_text=some_value", '=', 9},
{"☺a", 'a', 3},
{"a☻☺b", '', 4},
}
- Embedded lock
var hits struct {
sync.Mutex
n int
}
hits.Lock()
hits.n++
hits.Unlock()
* 2. Nested structs
- Decoding deeply nested JSON data
{"data": {"children": [
{"data": {
"title": "The Go homepage",
"url": "http://golang.org/"
}},
...
]}}
type Item struct {
Title string
URL string
}
type Response struct {
Data struct {
Children []struct {
Data Item
}
}
}
* 3. Command-line godoc
% godoc sync Mutex
PACKAGE
package sync
import "sync"
TYPES
type Mutex struct {
// contains filtered or unexported fields
}
A Mutex is a mutual exclusion lock. Mutexes can be created as part of
other structures; the zero value for a Mutex is an unlocked mutex.
func (m *Mutex) Lock()
Lock locks m. If the lock is already in use, the calling goroutine
blocks until the mutex is available.
func (m *Mutex) Unlock()
Unlock unlocks m. It is a run-time error if m is not locked on entry to
Unlock.
A locked Mutex is not associated with a particular goroutine. It is
allowed for one goroutine to lock a Mutex and then arrange for another
goroutine to unlock it.
* 4. godoc -src
% godoc -src sync Mutex
// A Mutex is a mutual exclusion lock.
// Mutexes can be created as part of other structures;
// the zero value for a Mutex is an unlocked mutex.
type Mutex struct {
state int32
sema uint32
}
Also shows unexported state! Great for digging around.
* 5. go get supports custom domains
Yep:
go get camlistore.org/pkg/netutil
See `go help importpath` for the details.
* 6. Mock out the file system
Got a package that works with the file system, but don't want your tests to actually use the disk?
var fs fileSystem = osFS{}
type fileSystem interface {
Open(name string) (file, error)
Stat(name string) (os.FileInfo, error)
}
type file interface {
io.Closer
io.Reader
io.ReaderAt
io.Seeker
Stat() (os.FileInfo, error)
}
// osFS implements fileSystem using the local disk.
type osFS struct{}
func (osFS) Open(name string) (file, error) { return os.Open(name) }
func (osFS) Stat(name string) (os.FileInfo, error) { return os.Stat(name) }
Implement your own fake `fileSystem` in and put it in `fs` while testing.
* 7. Method expressions
type T struct {}
func (T) Foo(s string) { println(s) }
var fn func(T, string) = T.Foo
Real example from `os/exec`:
func (c *Cmd) stdin() (f *os.File, err error)
func (c *Cmd) stdout() (f *os.File, err error)
func (c *Cmd) stderr() (f *os.File, err error)
type F func(*Cmd) (*os.File, error)
for _, setupFd := range []F{(*Cmd).stdin, (*Cmd).stdout, (*Cmd).stderr} {
fd, err := setupFd(c)
if err != nil {
c.closeDescriptors(c.closeAfterStart)
c.closeDescriptors(c.closeAfterWait)
return err
}
c.childFiles = append(c.childFiles, fd)
}
* 8. Send and receive on the same channel
.play 10things/8.go
* 9. Using close to broadcast
.play 10things/9.go /func.waiter/,/endmain/
* 9b. Using close to broadcast
.play 10things/9b.go /func.worker/,/endmain/
* 10. Nil channel in select
.play 10things/10.go /func.worker/,/endmain/
* 11. The gopher's name
.image 10things/gopher.jpg