收集了一些 Golang 代码片段.
强类型语言的鸭子类型
https://books.studygolang.com/gopl-zh/ch7/ch7-12.html
// writeString writes s to w.
// If w has a WriteString method, it is invoked instead of w.Write.
func writeString(w io.Writer, s string) (n int, err error) {
type stringWriter interface {
WriteString(string) (n int, err error)
}
if sw, ok := w.(stringWriter); ok {
return sw.WriteString(s) // avoid a copy
}
return w.Write([]byte(s)) // allocate temporary copy
}
package 级别变量, 首字母大写暗示常量的语义
https://github.com/golang/go/blob/release-branch.go1.15/src/flag/flag.go#L1010-L1013
// CommandLine is the default set of command-line flags, parsed from os.Args.
// The top-level functions such as BoolVar, Arg, and so on are wrappers for the
// methods of CommandLine.
var CommandLine = NewFlagSet(os.Args[0], ExitOnError)
公开方法包装私有属性
https://github.com/golang/go/blob/release-branch.go1.15/src/flag/flag.go#L993-L996
// Parsed reports whether f.Parse has been called.
func (f *FlagSet) Parsed() bool {
return f.parsed
}
组合 goroutine 的返回
// makeThumbnails6 makes thumbnails for each file received from the channel.
// It returns the number of bytes occupied by the files it creates.
func makeThumbnails6(filenames <-chan string) int64 {
sizes := make(chan int64)
var wg sync.WaitGroup // number of working goroutines
for f := range filenames {
wg.Add(1)
// worker
go func(f string) {
defer wg.Done()
thumb, err := thumbnail.ImageFile(f)
if err != nil {
log.Println(err)
return
}
info, _ := os.Stat(thumb) // OK to ignore error
sizes <- info.Size()
}(f)
}
// closer
go func() {
wg.Wait()
close(sizes)
}()
var total int64
for size := range sizes {
total += size
}
return total
}
sizes
是一个 channel, goroutine 中每计算完一项, 都把各自部分的 size 塞入 sizes
.
对 sizes
使用 range 迭代, 计算 sizes
的总和, 待 sizes
被 close 的时候迭代结束.
在单独的 goroutine 中 wg.Wait()
, 等各个部分结束后 close(sizes)
, 主 goroutine 的 range 从而得以退出.
这个例子之所以使用如此复杂的多个 goroutine 相互交织, 根本原因是我们不知道 filenames 的规模.
如果入参是一个明确 cap 的 slice, 我们就可以使用 buffer 先收集结果, 在主 goroutine 中 wait, 最后统一计算总和.
用 channel 并发限流
https://github.com/adonovan/gopl.io/blob/master/ch8/crawl2/findlinks.go#L20-L37
// tokens is a counting semaphore used to
// enforce a limit of 20 concurrent requests.
var tokens = make(chan struct{}, 20)
func crawl(url string) []string {
tokens <- struct{}{} // acquire a token
list, err := links.Extract(url)
<-tokens // release the token
return list
}
带容量的 channel 是天然的限流工具, 当容量满了之后, 再加入则会等待.