包形式解码url。将值输入value(s)和编码将值输入url.Values。

具有以下特点:

  • 支持几乎所有类型的映射。
  • 同时支持编号数组和普通数组。“数组[0]”和只是“数组”的多个值传递。
  • Slice尊重指定的索引。如。如果“Slice[2]”是传递下来的唯一的Slice值,那么它将被放在索引2处;如果slice不够大,它将被扩展。
  • 数组尊重指定的索引。如。如果“数组[2]”是唯一传递下来的数组值,它将被放在下标2处;如果数组不够大,将打印警告并忽略值。
  • 只在必要时创建对象。如果没有传递数组或映射值,则数组和映射在结构中保留默认值。
  • 允许自定义类型注册。
  • 处理时间。时间默认使用RFC3339时间格式,但是可以通过注册自定义类型轻松更改,见下面。
  • 处理编码和解码的几乎所有的Go类型。可以解码成结构,数组,映射,int…编码struct, array, map, int…

常见问题

  • 它支持编码。textunmarshaler吗?不,因为TextUnmarshaler只接受[] byte,但是发布的值可以有多个值,所以不合适。
  • array/slicearray[idx]/slice[idx]的混合,它们是按照什么顺序解析的?array/slice然后array[idx]/slice[idx]

**

支持的类型(开箱即用)

  • string
  • bool
  • int, int8, int16, int32, int64
  • uint, uint8, uint16, uint32, uint64
  • float32, float64
  • struct and anonymous struct
  • interface{}
  • time.Time - by default using RFC3339
  • a pointer to one of the above types
  • slice, array
  • map
  • custom types 可以覆盖上面的任何类型
  • 可能天生就支持许多其他类型

注意:map、struct和slice嵌套是无限的。

安装


使用 go get

  1. go get github.com/go-playground/form

然后将表单包导入到自己的代码中。

  1. import "github.com/go-playground/form/v4"

使用


  • 使用符号。分隔fields/structs。(如。structfield.field)
  • 使用[索引或键]访问一个slice/array的索引,或使用键访问map。(如。arrayfield [0], mapfield [keyvalue])


  1. <form method="POST">
  2. <input type="text" name="Name" value="joeybloggs"/>
  3. <input type="text" name="Age" value="3"/>
  4. <input type="text" name="Gender" value="Male"/>
  5. <input type="text" name="Address[0].Name" value="26 Here Blvd."/>
  6. <input type="text" name="Address[0].Phone" value="9(999)999-9999"/>
  7. <input type="text" name="Address[1].Name" value="26 There Blvd."/>
  8. <input type="text" name="Address[1].Phone" value="1(111)111-1111"/>
  9. <input type="text" name="active" value="true"/>
  10. <input type="text" name="MapExample[key]" value="value"/>
  11. <input type="text" name="NestedMap[key][key]" value="value"/>
  12. <input type="text" name="NestedArray[0][0]" value="value"/>
  13. <input type="submit"/>
  14. </form>

例子


解码

  1. package main
  2. import (
  3. "fmt"
  4. "log"
  5. "net/url"
  6. "github.com/go-playground/form/v4"
  7. )
  8. // Address contains address information
  9. type Address struct {
  10. Name string
  11. Phone string
  12. }
  13. // User contains user information
  14. type User struct {
  15. Name string
  16. Age uint8
  17. Gender string
  18. Address []Address
  19. Active bool `form:"active"`
  20. MapExample map[string]string
  21. NestedMap map[string]map[string]string
  22. NestedArray [][]string
  23. }
  24. // use a single instance of Decoder, it caches struct info
  25. //使用单一的解码器实例,它缓存结构信息
  26. var decoder *form.Decoder
  27. func main() {
  28. decoder = form.NewDecoder()
  29. // this simulates the results of http.Request's ParseForm() function
  30. //这将模拟http的结果。请求的ParseForm()函数
  31. values := parseForm()
  32. var user User
  33. // must pass a pointer
  34. //必须传递一个指针
  35. err := decoder.Decode(&user, values)
  36. if err != nil {
  37. log.Panic(err)
  38. }
  39. fmt.Printf("%#v\n", user)
  40. }
  41. // this simulates the results of http.Request's ParseForm() function
  42. //这将模拟http的结果。请求的ParseForm()函数
  43. func parseForm() url.Values {
  44. return url.Values{
  45. "Name": []string{"joeybloggs"},
  46. "Age": []string{"3"},
  47. "Gender": []string{"Male"},
  48. "Address[0].Name": []string{"26 Here Blvd."},
  49. "Address[0].Phone": []string{"9(999)999-9999"},
  50. "Address[1].Name": []string{"26 There Blvd."},
  51. "Address[1].Phone": []string{"1(111)111-1111"},
  52. "active": []string{"true"},
  53. "MapExample[key]": []string{"value"},
  54. "NestedMap[key][key]": []string{"value"},
  55. "NestedArray[0][0]": []string{"value"},
  56. }
  57. }

编码

  1. package main
  2. import (
  3. "fmt"
  4. "log"
  5. "github.com/go-playground/form/v4"
  6. )
  7. // Address contains address information
  8. //地址包含地址信息
  9. type Address struct {
  10. Name string
  11. Phone string
  12. }
  13. // User contains user information
  14. //User包含用户信息
  15. type User struct {
  16. Name string
  17. Age uint8
  18. Gender string
  19. Address []Address
  20. Active bool `form:"active"`
  21. MapExample map[string]string
  22. NestedMap map[string]map[string]string
  23. NestedArray [][]string
  24. }
  25. // use a single instance of Encoder, it caches struct info
  26. //使用单一的编码器实例,它缓存结构信息
  27. var encoder *form.Encoder
  28. func main() {
  29. encoder = form.NewEncoder()
  30. user := User{
  31. Name: "joeybloggs",
  32. Age: 3,
  33. Gender: "Male",
  34. Address: []Address{
  35. {Name: "26 Here Blvd.", Phone: "9(999)999-9999"},
  36. {Name: "26 There Blvd.", Phone: "1(111)111-1111"},
  37. },
  38. Active: true,
  39. MapExample: map[string]string{"key": "value"},
  40. NestedMap: map[string]map[string]string{"key": {"key": "value"}},
  41. NestedArray: [][]string{{"value"}},
  42. }
  43. // must pass a pointer
  44. values, err := encoder.Encode(&user)
  45. if err != nil {
  46. log.Panic(err)
  47. }
  48. fmt.Printf("%#v\n", values)
  49. }

注册自定义类型


解码器

  1. decoder.RegisterCustomTypeFunc(func(vals []string) (interface{}, error) {
  2. return time.Parse("2006-01-02", vals[0])
  3. }, time.Time{})

附加:如果注册了一个结构类型,该函数将只在url时被调用。值为结构而存在,而不仅仅是结构字段。url。value {“User”:”Name%3Djoeybloggs”}将调用以’User’为类型的自定义类型函数,但是url.Values{“User.Name”:”joeybloggs”}不会。

编码器

  1. encoder.RegisterCustomTypeFunc(func(x interface{}) ([]string, error) {
  2. return []string{x.(time.Time).Format("2006-01-02")}, nil
  3. }, time.Time{})

忽略字段


您可以告诉form在标记中使用-忽略字段

  1. type MyStruct struct {
  2. Field string `form:"-"`
  3. }

忽略空值


您可以告诉form在标签中使用omitempty或FieldName omitempty来省略空字段

  1. type MyStruct struct {
  2. Field string `form:",omitempty"`
  3. Field2 string `form:"CustomFieldName,omitempty"`
  4. }

注意


为了最大化与其他系统的兼容性,编码器试图避免在url中使用数组索引。值,如果可能的话。
例如

  1. // A struct field of
  2. Field []string{"1", "2", "3"}
  3. // will be output a url.Value as
  4. "Field": []string{"1", "2", "3"}
  5. and not
  6. "Field[0]": []string{"1"}
  7. "Field[1]": []string{"2"}
  8. "Field[2]": []string{"3"}
  9. // however there are times where it is unavoidable, like with pointers
  10. // 然而,有些时候这是不可避免的,比如指针
  11. i := int(1)
  12. Field []*string{nil, nil, &i}
  13. // to avoid index 1 and 2 must use index
  14. "Field[2]": []string{"1"}

基准测试程序数值

注意:前4个解码中的1分配和B/op实际上是传递它时的结构分配,所以原语实际上是零分配。

  1. go test -run=NONE -bench=. -benchmem=true
  2. goos: darwin
  3. goarch: amd64
  4. pkg: github.com/go-playground/form/benchmarks
  5. BenchmarkSimpleUserDecodeStruct-8 5000000 236 ns/op 64 B/op 1 allocs/op
  6. BenchmarkSimpleUserDecodeStructParallel-8 20000000 82.1 ns/op 64 B/op 1 allocs/op
  7. BenchmarkSimpleUserEncodeStruct-8 2000000 627 ns/op 485 B/op 10 allocs/op
  8. BenchmarkSimpleUserEncodeStructParallel-8 10000000 223 ns/op 485 B/op 10 allocs/op
  9. BenchmarkPrimitivesDecodeStructAllPrimitivesTypes-8 2000000 724 ns/op 96 B/op 1 allocs/op
  10. BenchmarkPrimitivesDecodeStructAllPrimitivesTypesParallel-8 10000000 246 ns/op 96 B/op 1 allocs/op
  11. BenchmarkPrimitivesEncodeStructAllPrimitivesTypes-8 500000 3187 ns/op 2977 B/op 36 allocs/op
  12. BenchmarkPrimitivesEncodeStructAllPrimitivesTypesParallel-8 1000000 1106 ns/op 2977 B/op 36 allocs/op
  13. BenchmarkComplexArrayDecodeStructAllTypes-8 100000 13748 ns/op 2248 B/op 121 allocs/op
  14. BenchmarkComplexArrayDecodeStructAllTypesParallel-8 500000 4313 ns/op 2249 B/op 121 allocs/op
  15. BenchmarkComplexArrayEncodeStructAllTypes-8 200000 10758 ns/op 7113 B/op 104 allocs/op
  16. BenchmarkComplexArrayEncodeStructAllTypesParallel-8 500000 3532 ns/op 7113 B/op 104 allocs/op
  17. BenchmarkComplexMapDecodeStructAllTypes-8 100000 17644 ns/op 5305 B/op 130 allocs/op
  18. BenchmarkComplexMapDecodeStructAllTypesParallel-8 300000 5470 ns/op 5308 B/op 130 allocs/op
  19. BenchmarkComplexMapEncodeStructAllTypes-8 200000 11155 ns/op 6971 B/op 129 allocs/op
  20. BenchmarkComplexMapEncodeStructAllTypesParallel-8 500000 3768 ns/op 6971 B/op 129 allocs/op
  21. BenchmarkDecodeNestedStruct-8 500000 2462 ns/op 384 B/op 14 allocs/op
  22. BenchmarkDecodeNestedStructParallel-8 2000000 814 ns/op 384 B/op 14 allocs/op
  23. BenchmarkEncodeNestedStruct-8 1000000 1483 ns/op 693 B/op 16 allocs/op
  24. BenchmarkEncodeNestedStructParallel-8 3000000 525 ns/op 693 B/op 16 allocs/op

竞争对手的基准可以在这里找到

免费软件


下面是一个软件列表,它们使用这个库进行解码。

  • Validator-去结构和字段验证,包括字段,结构,映射,切片和数组潜水。
  • mold-是一个通用库,用于帮助修改或设置数据结构和其他对象中的数据。