func (ft fieldTree) matchPrefix(p cmp.Path) bool {
	for _, ps := range p {
		switch ps := ps.(type) {
		case cmp.StructField:
			ft = ft.sub[ps.Name()]
			if ft.ok {
				return true
			}
			if len(ft.sub) == 0 {
				return false
			}
		case cmp.Indirect:
		default:
			return false
		}
	}
	return false
}
matchPrefix reports whether any selector in the fieldTree matches
the start of path p.
package cmpopts
import (
	"fmt"
	"reflect"
	"strings"
	"github.com/google/go-cmp/cmp"
)
func filterField(typ interface{}, name string, opt cmp.Option) cmp.Option {
	sf := newStructFilter(typ, name)
	return cmp.FilterPath(sf.filter, opt)
}
type structFilter struct {
	t  reflect.Type  
	ft fieldTree     
}
func newStructFilter(typ interface{}, names ...string) structFilter {
	t := reflect.TypeOf(typ)
	if t == nil || t.Kind() != reflect.Struct {
		panic(fmt.Sprintf("%T must be a struct", typ))
	}
	var ft fieldTree
	for _, name := range names {
		cname, err := canonicalName(t, name)
		if err != nil {
			panic(fmt.Sprintf("%s: %v", strings.Join(cname, "."), err))
		}
		ft.insert(cname)
	}
	return structFilter{t, ft}
}
func (sf structFilter) filter(p cmp.Path) bool {
	for i, ps := range p {
		if ps.Type().AssignableTo(sf.t) && sf.ft.matchPrefix(p[i+1:]) {
			return true
		}
	}
	return false
}
type fieldTree struct {
	ok  bool                  
	sub map[string]fieldTree  
}
func (ft *fieldTree) insert(cname []string) {
	if ft.sub == nil {
		ft.sub = make(map[string]fieldTree)
	}
	if len(cname) == 0 {
		ft.ok = true
		return
	}
	sub := ft.sub[cname[0]]
	sub.insert(cname[1:])
	ft.sub[cname[0]] = sub
}