code: func (w *walker) lock(v reflect.Value) {
  	if !w.useLocks {
  		return
  	}
  
  	if !v.IsValid() || !v.CanInterface() {
  		return
  	}
  
  	type rlocker interface {
  		RLocker() sync.Locker
  	}
  
  	var locker sync.Locker
  
  	// We can't call Interface() on a value directly, since that requires
  	// a copy. This is OK, since the pointer to a value which is a sync.Locker
  	// is also a sync.Locker.
  	if v.Kind() == reflect.Ptr {
  		switch l := v.Interface().(type) {
  		case rlocker:
  			// don't lock a mutex directly
  			if _, ok := l.(*sync.RWMutex); !ok {
  				locker = l.RLocker()
  			}
  		case sync.Locker:
  			locker = l
  		}
  	} else if v.CanAddr() {
  		switch l := v.Addr().Interface().(type) {
  		case rlocker:
  			// don't lock a mutex directly
  			if _, ok := l.(*sync.RWMutex); !ok {
  				locker = l.RLocker()
  			}
  		case sync.Locker:
  			locker = l
  		}
  	}
  
  	// still no callable locker
  	if locker == nil {
  		return
  	}
  
  	// don't lock a mutex directly
  	switch locker.(type) {
  	case *sync.Mutex, *sync.RWMutex:
  		return
  	}
  
  	locker.Lock()
  	w.locks[w.depth] = locker
  }
docs: // if this value is a Locker, lock it and add it to the locks slice