func walkStruct(form url.Values, path string, val reflect.Value) (reflect.Value, errorlist.List) {
	var el errorlist.List
	cpy := reflect.New(val.Type()).Elem()
	cpy.Set(reflect.Zero(val.Type()))  
	for i := 0; i < val.NumField(); i++ {
		field := val.Field(i)
		name := val.Type().Field(i).Name
		if unexported(name) || unwalkable(field) {
			continue
		}
		fieldCpy, err := walk(form, path+"."+name, field)
		if err != nil {
			el = el.Append(err)
		}
		cpy.Field(i).Set(fieldCpy)
	}
	return cpy, el
}
----------------------------------------------------------------------------
Structures
Structs are easy: all fields are fixed, nothing to add or delete.
package gui
import (
	"fmt"
	"html/template"
	"net/url"
	"reflect"
	"strconv"
	"time"
	"github.com/vdobler/ht/errorlist"
)
type ValueError struct {
	Path string  
	Err  error   
}
func (ve ValueError) Error() string {
	return fmt.Sprintf("field %s: %s", ve.Path, ve.Err.Error())
}
func newValueErrorList(path string, err error) errorlist.List {
	if err == nil {
		return nil
	}
	return errorlist.List{ValueError{Path: path, Err: err}}
}
type addNoticeError string
func (addNoticeError) Error() string { return "-- all is fine --" }
func walk(form url.Values, path string, val reflect.Value) (reflect.Value, errorlist.List) {
	switch val.Kind() {
	case reflect.Bool:
		return walkBool(form, path, val)
	case reflect.String:
		return walkString(form, path, val)
	case reflect.Int64:
		if isDuration(val) {
			return walkDuration(form, path, val)
		}
		fallthrough
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32:
		return walkInt(form, path, val)
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
		return walkUint(form, path, val)
	case reflect.Float64, reflect.Float32:
		return walkFloat64(form, path, val)
	case reflect.Struct:
		if isTime(val) {
			return walkTime(form, path, val)
		}
		return walkStruct(form, path, val)
	case reflect.Map:
		return walkMap(form, path, val)
	case reflect.Slice:
		return walkSlice(form, path, val)
	case reflect.Interface:
		return walkInterface(form, path, val)
	case reflect.Ptr:
		return walkPtr(form, path, val)
	}
	fmt.Println("gui: won't walk over", val.Kind().String(), "in", path)
	return reflect.Value{}, nil
}
func walkBool(form url.Values, path string, val reflect.Value) (reflect.Value, errorlist.List) {
	cpy := reflect.New(val.Type()).Elem()
	if _, ok := form[path]; ok {
		delete(form, path)
		cpy.SetBool(true)
	} else {
		cpy.SetBool(false)
	}
	return cpy, nil
}
func walkString(form url.Values, path string, val reflect.Value) (reflect.Value, errorlist.List) {
	cpy := reflect.New(val.Type()).Elem()
	cpy.SetString(val.String())
	if newVals, ok := form[path]; ok {
		delete(form, path)
		if len(newVals) == 1 {
			cpy.SetString(newVals[0])
		} else {
			nv := ""
			for _, v := range newVals {
				if v == "" {
					continue
				}
				if nv != "" {
					nv += " "
				}
				nv += v
			}
			cpy.SetString(nv)
		}
	}
	return cpy, nil
}
func walkDuration(form url.Values, path string, val reflect.Value) (reflect.Value, errorlist.List) {
	cpy := reflect.New(val.Type()).Elem()
	cpy.SetInt(val.Int())
	if newVals, ok := form[path]; ok {
		delete(form, path)
		newval, err := time.ParseDuration(newVals[0])
		if err != nil {
			return cpy, newValueErrorList(path, err)
		}
		cpy.SetInt(int64(newval))
	}
	return cpy, nil
}
func walkTime(form url.Values, path string, val reflect.Value) (reflect.Value, errorlist.List) {
	cpy := reflect.New(val.Type()).Elem()
	cpy.Set(val)
	if newVals, ok := form[path]; ok {
		delete(form, path)
		newval, err := time.Parse(timeFormat, newVals[0])
		if err != nil {
			return cpy, newValueErrorList(path, err)
		}
		cpy.Set(reflect.ValueOf(newval))
	}
	return cpy, nil
}
func walkInt(form url.Values, path string, val reflect.Value) (reflect.Value, errorlist.List) {
	cpy := reflect.New(val.Type()).Elem()
	cpy.SetInt(val.Int())
	if newVals, ok := form[path]; ok {
		delete(form, path)
		newVal, err := strconv.ParseInt(newVals[0], 10, 64)
		if err != nil {
			return cpy, newValueErrorList(path, err)
		}
		cpy.SetInt(newVal)
	}
	return cpy, nil
}
func walkUint(form url.Values, path string, val reflect.Value) (reflect.Value, errorlist.List) {
	cpy := reflect.New(val.Type()).Elem()
	cpy.SetUint(val.Uint())
	if newVals, ok := form[path]; ok {
		delete(form, path)
		newVal, err := strconv.ParseInt(newVals[0], 10, 64)
		if err != nil {
			return cpy, newValueErrorList(path, err)
		}
		cpy.SetUint(uint64(newVal))  
	}
	return cpy, nil
}
func walkFloat64(form url.Values, path string, val reflect.Value) (reflect.Value, errorlist.List) {
	cpy := reflect.New(val.Type()).Elem()
	cpy.SetFloat(val.Float())
	if newVals, ok := form[path]; ok {
		delete(form, path)
		newVal, err := strconv.ParseFloat(newVals[0], 64)
		if err != nil {
			return cpy, newValueErrorList(path, err)
		}
		cpy.SetFloat(newVal)
	}
	return cpy, nil
}
func walkPtr(form url.Values, path string, val reflect.Value) (reflect.Value, errorlist.List) {
	if val.IsNil() {
		return walkNilPtr(form, path, val)
	}
	return walkNonNilPtr(form, path, val)
}
func walkNonNilPtr(form url.Values, path string, val reflect.Value) (reflect.Value, errorlist.List) {
	op := path + ".__OP__"
	if form.Get(op) == "Remove" {
		delete(form, op)
		delete(form, path)
		return reflect.Zero(val.Type()), nil
	}
	elemcpy, err := walk(form, path, val.Elem())
	cpy := reflect.New(val.Type()).Elem()
	cpy.Set(elemcpy.Addr())
	return cpy, err
}
func walkNilPtr(form url.Values, path string, val reflect.Value) (reflect.Value, errorlist.List) {
	op := path + ".__OP__"
	if form.Get(op) == "Add" {
		delete(form, op)
		delete(form, path)
		elemTyp := val.Type().Elem()
		elem := reflect.New(elemTyp).Elem()
		elem.Set(reflect.Zero(elemTyp))
		err := addNoticeError(path)
		return elem.Addr(), errorlist.List{err}
	}
	return reflect.Zero(val.Type()), nil
}
func walkInterface(form url.Values, path string, val reflect.Value) (reflect.Value, errorlist.List) {
	if val.IsNil() {
		return walkNilInterface(form, path, val)
	}
	return walkNonNilInterface(form, path, val)
}
func walkNonNilInterface(form url.Values, path string, val reflect.Value) (reflect.Value, errorlist.List) {
	op := path + ".__OP__"
	if form.Get(op) == "Remove" {
		delete(form, op)
		delete(form, path)
		return reflect.Zero(val.Type()), nil
	}
	elemcpy, err := walk(form, path, val.Elem())
	cpy := reflect.New(val.Type()).Elem()
	cpy.Set(elemcpy)
	return cpy, err
}
func walkNilInterface(form url.Values, path string, val reflect.Value) (reflect.Value, errorlist.List) {
	op := path + ".__TYPE__"
	if name := form.Get(op); name != "" {
		delete(form, op)
		delete(form, path)
		for _, implementor := range Implements[val.Type()] {
			ptr := implementor.Kind() == reflect.Ptr
			implName := implementor.Name()
			if ptr {
				implName = implementor.Elem().Name()
			}
			if implName == name {
				elem := reflect.New(implementor).Elem()
				if ptr {
					elem.Set(reflect.New(implementor.Elem()))
				} else {
					elem.Set(reflect.Zero(implementor))
				}
				err := addNoticeError(path)
				return elem, errorlist.List{err}
			}
		}
		return reflect.Zero(val.Type()),
			newValueErrorList(path, fmt.Errorf("No such type %s", name))
	}
	return reflect.Zero(val.Type()), nil
}