func deepHash(src reflect.Value, visited map[uintptr]*visit, depth int) []byte {
	if !src.IsValid() {
		return nil
	}
	if src.CanAddr() {
		addr := src.UnsafeAddr()
		h := 17 * addr
		seen := visited[h]
		typ := src.Type()
		for p := seen; p != nil; p = p.next {
			if p.ptr == addr && p.typ == typ {
				return nil
			}
		}
		visited[h] = &visit{addr, typ, seen}
	}
	hash := fnv.New64a()
	for src.Kind() == reflect.Ptr || src.Kind() == reflect.Interface {
		src = src.Elem()
	}
	switch src.Kind() {
	case reflect.Struct:
		for i, n := 0, src.NumField(); i < n; i++ {
			if b := deepHash(src.Field(i), visited, depth+1); b != nil {
				hash.Write(b)
			}
		}
	case reflect.Map:
		sortedHashedKeys := make([]string, len(src.MapKeys()))
		indexedByHash := make(map[string]reflect.Value)
		for i, key := range src.MapKeys() {
			kh := fmt.Sprintf("%x", deepHash(key, visited, depth+1))
			sortedHashedKeys[i] = kh
			indexedByHash[kh] = src.MapIndex(key)
		}
		sort.Strings(sortedHashedKeys)
		for _, kh := range sortedHashedKeys {
			hash.Write([]byte(kh))
			hash.Write(deepHash(indexedByHash[kh], visited, depth+1))
		}
	case reflect.Slice, reflect.Array:
		for i := 0; i < src.Len(); i++ {
			hash.Write(deepHash(src.Index(i), visited, depth+1))
		}
	case reflect.String:
		hash.Write([]byte(src.String()))
	case reflect.Bool:
		if src.Bool() == true {
			hash.Write([]byte("1"))
		} else {
			hash.Write([]byte("0"))
		}
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		binary.Write(hash, binary.BigEndian, src.Int())
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		binary.Write(hash, binary.BigEndian, src.Uint())
	case reflect.Float32, reflect.Float64:
		binary.Write(hash, binary.BigEndian, src.Float())
	}
	return hash.Sum(nil)
}
Traverses recursively hashing each exported value
package deephash
import (
	"encoding/binary"
	"fmt"
	"hash/fnv"
	"reflect"
	"sort"
)
type visit struct {
	ptr  uintptr
	typ  reflect.Type
	next *visit
}