妙用Go类型定义避免循环引用

类型定义(Type Definition)

type MyInt int
  • 创建一个新类型,与底层类型(underlying type)不同。
  • 新类型拥有独立的类型集,不会继承底层类型的方法
  • 需要进行显式类型转换才能与底层类型互用

巧妙使用类型定义来避免对象实例方法循环调用

// file: github.com/powerman/rpc-codec/blob/master/jsonrpc2/client.go

type clientResponse struct {
	Version string           `json:"jsonrpc"`
	ID      *uint64          `json:"id"`
	Result  *json.RawMessage `json:"result,omitempty"`
	Error   *Error           `json:"error,omitempty"`
}

func (r *clientResponse) reset() {
	r.Version = ""
	r.ID = nil
	r.Result = nil
	r.Error = nil
}

func (r *clientResponse) UnmarshalJSON(raw []byte) error {
	r.reset()
	type resp *clientResponse // 非常关键的一个动作,要身不要心
	if err := json.Unmarshal(raw, resp(r)); err != nil {
		return errors.New("bad response: " + string(raw))
	}

	var o = make(map[string]*json.RawMessage)
	if err := json.Unmarshal(raw, &o); err != nil {
		return errors.New("bad response: " + string(raw))
	}

	// ...other logic...

	return nil
}

看上面代码, clientResponse.UnmarshalJSON(...) 自定义实现 json.Unmarshaler 接口来 反序列化自身,内部逻辑使用json.Unmarshal(raw, resp(r))执行解码操作,type resp *clientResponseresp(r) 配合使用后,将 (r *clientResponse) 实例对象 变成了一个 纯 结构体对象,只包含数据结构,没有任何方法,这就避免了 原 *clientResponse 对象因为实现了 json.Unmarshaler 接口,如果直接调用 json.Unmarshal(raw, r),就会出现循环调用该方法自身。

type resp *clientResponseresp(r) 的作用就有点类似于 只要身子不要心,这么说来,有一点点 渣渣 ~哈~

// Unmarshaler is the interface implemented by types
// that can unmarshal a JSON description of themselves.
// The input can be assumed to be a valid encoding of
// a JSON value. UnmarshalJSON must copy the JSON data
// if it wishes to retain the data after returning.
type Unmarshaler interface {
	UnmarshalJSON([]byte) error
}
 女孩