Go Code Fragment


收集了一些 Golang 代码片段.



// 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 级别变量, 首字母大写暗示常量的语义


// 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)



// 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 {
		// worker
		go func(f string) {
			defer wg.Done()
			thumb, err := thumbnail.ImageFile(f)
			if err != nil {
			info, _ := os.Stat(thumb) // OK to ignore error
			sizes <- info.Size()

	// closer
	go func() {

	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 并发限流


// 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 是天然的限流工具, 当容量满了之后, 再加入则会等待.