code: func Cast(data interface{}, params params.Params, fields []string, opts ...Option) *Changeset {
  	options := Options{
  		message:     CastErrorMessage,
  		emptyValues: []interface{}{""},
  	}
  	options.apply(opts)
  
  	var ch *Changeset
  	if existingCh, ok := data.(Changeset); ok {
  		ch = &existingCh
  	} else if existingCh, ok := data.(*Changeset); ok {
  		ch = existingCh
  	} else {
  		ch = &Changeset{}
  		ch.params = params
  		ch.changes = make(map[string]interface{})
  		ch.values, ch.types, ch.zero = mapSchema(data)
  	}
  
  	for _, field := range fields {
  		typ, texist := ch.types[field]
  
  		if !params.Exists(field) || !texist {
  			continue
  		}
  
  		// ignore if it's an empty value
  		if contains(options.emptyValues, params.Get(field)) {
  			continue
  		}
  
  		if change, valid := params.GetWithType(field, typ); valid {
  			value, vexist := ch.values[field]
  
  			if (typ.Kind() == reflect.Slice || typ.Kind() == reflect.Array) || (ch.zero && change != nil) || (!vexist && change != nil) || (vexist && value != change) {
  				ch.changes[field] = change
  			}
  		} else {
  			msg := strings.Replace(options.message, "{field}", field, 1)
  			AddError(ch, field, msg)
  		}
  	}
  
  	return ch
  }
docs: // Cast params as changes for the given data according to the permitted fields. Returns a new changeset.
  // params will only be added as changes if it does not have the same value as the field in the data.