匿名结构体
最常见的匿名用法,不用单独定义一个结构体类型
var config struct {
APIKey string
OAuthConfig oauth.Config
}
config.APIKey = "BADC0C0A"
匿名结构体定义时并初始化
data := struct {
Title string
Users []*User
}{
title,
users,
}
err := tmpl.Execute(w, data)
匿名结构体slice定义并初始化
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},
}
嵌套互斥锁
var hits struct {
sync.Mutex
n int
}
hits.Lock()
hits.n++
hits.Unlock()
嵌套结构体
type Item struct {
Title string
URL string
}
type Response struct {
Data struct {
Children []struct {
Data Item
}
}
}
命令行 go doc
在命令行中,可以通过go doc 查看包相关接口信息
wdy@wdy:~/learn/program-learn/golang$ go doc sync
package sync // import "sync"
Package sync provides basic synchronization primitives such as mutual
exclusion locks. Other than the Once and WaitGroup types, most are intended
for use by low-level library routines. Higher-level synchronization is
better done via channels and communication.
Values containing the types defined in this package should not be copied.
func NewCond(l Locker) *Cond
type Cond struct { ... }
type Locker interface { ... }
type Mutex struct { ... }
type Once struct { ... }
type Pool struct { ... }
type RWMutex struct { ... }
type WaitGroup struct { ... }
wdy@wdy:~/learn/program-learn/golang$ go doc sync Mutex
type Mutex struct {
// Has 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()
func (m *Mutex) Unlock()
wdy@wdy:~/learn/program-learn/golang$ go doc sync.mutex.lock
func (m *Mutex) Lock()
Lock locks m. If the lock is already in use, the calling goroutine blocks
until the mutex is available.
另外还有一个厉害的工具 ,执行下面命令
godoc -http :6061
会打开一个网页如下:
可以方便的查询各个package的相关知识。
在同一个channel上进行读写操作
battle是一个阻塞channel,当多个goroutine执行warrior的时候,最先执行到select的goroutine进入到
case battle <- name:
此时其他goroutine会阻塞在select上,name进入battle的瞬间,阻塞等待的goroutine的其中一个会进入到
case opponent := <-battle:
battle数据被读取后,阻塞等待的剩余的goroutine的其中一个会进入到
case battle <- name:
按照如上流程反复直到所有goroutine执行完毕。
var battle = make(chan string)
func warrior(name string, done chan struct{}) {
select {
case opponent := <-battle:
fmt.Printf("%s beat %s\n", name, opponent)
case battle <- name:
// I lost :-(
}
done <- struct{}{}
}
func main() {
done := make(chan struct{})
langs := []string{"Go", "C", "C++", "Java", "Perl", "Python"}
for _, l := range langs {
go warrior(l, done)
}
for _ = range langs {
<-done
}
}
可以看到每次结果都是不一样的
wdy@wdy:~/learn/program-learn/golang$ go run learnchannel.go
Go beat Python
C++ beat C
Java beat Perl
wdy@wdy:~/learn/program-learn/golang$ go run learnchannel.go
Perl beat Java
Python beat Go
C beat C++
wdy@wdy:~/learn/program-learn/golang$ go run learnchannel.go
C++ beat C
Java beat Perl
Python beat Go
wdy@wdy:~/learn/program-learn/golang$ go run learnchannel.go
Go beat Python
Perl beat Java
C beat C++
wdy@wdy:~/learn/program-learn/golang$ go run learnchannel.go
Python beat Go
C beat C++
Java beat Perl
wdy@wdy:~/learn/program-learn/golang$ go run learnchannel.go
Go beat Python
Perl beat Java
C beat C++
wdy@wdy:~/learn/program-learn/golang$ go run learnchannel.go
Go beat Python
C beat C++
Java beat Perl
利用close来向其他goroutine广播
func waiter(i int, block, done chan struct{}) {
time.Sleep(time.Duration(rand.Intn(3000)) * time.Millisecond)
fmt.Println(i, "waiting...")
<-block
fmt.Println(i, "done!")
done <- struct{}{}
}
func main() {
block, done := make(chan struct{}), make(chan struct{})
for i := 0; i < 4; i++ {
go waiter(i, block, done)
}
time.Sleep(5 * time.Second)
close(block)
for i := 0; i < 4; i++ {
<-done
}
}
结果
2 waiting...
1 waiting...
3 waiting...
0 waiting...
0 done!
3 done!
2 done!
1 done!
利用nil通道的特性
goroutine对于值为nil的channel进行接受或发送操作时,会永久block
type Work struct {
Job string
}
func (w Work) Do() {
fmt.Println("do", w.Job)
}
func (w Work) Refuse() {
fmt.Println(w.Job + "stopped")
}
func makeWork(ch chan Work) {
for {
time.Sleep(500 * time.Millisecond)
ch <- Work{Job: "job"}
}
}
func worker(i int, ch chan Work, quit chan struct{}) {
for {
select {
case w := <-ch:
if quit == nil {
w.Refuse()
fmt.Println("worker", i, "refused", w)
break
}
w.Do()
fmt.Println("worker", i, "processed", w)
case <-quit:
fmt.Println("worker", i, "quitting")
quit = nil
}
}
}
结果
do job
worker 0 processed {job}
do job
worker 1 processed {job}
do job
worker 2 processed {job}
do job
worker 3 processed {job}
do job
worker 0 processed {job}
do job
worker 1 processed {job}
do job
worker 2 processed {job}
do job
worker 3 processed {job}
do job
worker 0 processed {job}
worker 0 quitting
worker 1 quitting
worker 2 quitting
worker 3 quitting
jobstopped
worker 0 refused {job}
jobstopped
worker 1 refused {job}
jobstopped
worker 2 refused {job}
jobstopped
worker 3 refused {job}
后记
之前一直在CSDN上写文章,后面会逐步转换到简书上,还请大家多多支持。