🌝

从源码中学习优雅 Go 编程

Posted at — Sep 17, 2022

1. 巧妙使用 Context 包的 Value 函数

Go net 包源码中有一段如下代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
func (r *Resolver) lookupIPAddr(ctx context.Context, network, host string) ([]IPAddr, error) {
	// ...

	// The underlying resolver func is lookupIP by default but it
	// can be overridden by tests. This is needed by net/http, so it
	// uses a context key instead of unexported variables.
	resolverFunc := r.lookupIP
	if alt, _ := ctx.Value(nettrace.LookupIPAltResolverKey{}).(func(context.Context, string, string) ([]IPAddr, error)); alt != nil {
        resolverFunc = alt
    }
	
	// ...
}

他的主要目的是,不给 Resolver 增加成员变量,但同时能满足一些 go test 需要自定义 lookupIP 函数的需求:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
func TestTransportMaxIdleConns(t *testing.T) {
    // ...

	ctx := context.WithValue(context.Background(), nettrace.LookupIPAltResolverKey{}, func(ctx context.Context, _, host string) ([]net.IPAddr, error) {
        return []net.IPAddr{{IP: net.ParseIP(ip)}}, nil
    })


    // ...
}