包形式解码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/slice 与 array[idx]/slice[idx]的混合,它们是按照什么顺序解析的?array/slice然后array[idx]/slice[idx]
支持的类型(开箱即用)
stringboolint,int8,int16,int32,int64uint,uint8,uint16,uint32,uint64float32,float64structandanonymous structinterface{}time.Time- by default using RFC3339- a
pointerto one of the above types slice,arraymapcustom types可以覆盖上面的任何类型- 可能天生就支持许多其他类型
注意:map、struct和slice嵌套是无限的。
安装
使用 go get
go get github.com/go-playground/form
然后将表单包导入到自己的代码中。
import "github.com/go-playground/form/v4"
使用
- 使用符号。分隔fields/structs。(如。structfield.field)
- 使用[索引或键]访问一个slice/array的索引,或使用键访问map。(如。arrayfield [0], mapfield [keyvalue])
<form method="POST"><input type="text" name="Name" value="joeybloggs"/><input type="text" name="Age" value="3"/><input type="text" name="Gender" value="Male"/><input type="text" name="Address[0].Name" value="26 Here Blvd."/><input type="text" name="Address[0].Phone" value="9(999)999-9999"/><input type="text" name="Address[1].Name" value="26 There Blvd."/><input type="text" name="Address[1].Phone" value="1(111)111-1111"/><input type="text" name="active" value="true"/><input type="text" name="MapExample[key]" value="value"/><input type="text" name="NestedMap[key][key]" value="value"/><input type="text" name="NestedArray[0][0]" value="value"/><input type="submit"/></form>
例子
解码
package mainimport ("fmt""log""net/url""github.com/go-playground/form/v4")// Address contains address informationtype Address struct {Name stringPhone string}// User contains user informationtype User struct {Name stringAge uint8Gender stringAddress []AddressActive bool `form:"active"`MapExample map[string]stringNestedMap map[string]map[string]stringNestedArray [][]string}// use a single instance of Decoder, it caches struct info//使用单一的解码器实例,它缓存结构信息var decoder *form.Decoderfunc main() {decoder = form.NewDecoder()// this simulates the results of http.Request's ParseForm() function//这将模拟http的结果。请求的ParseForm()函数values := parseForm()var user User// must pass a pointer//必须传递一个指针err := decoder.Decode(&user, values)if err != nil {log.Panic(err)}fmt.Printf("%#v\n", user)}// this simulates the results of http.Request's ParseForm() function//这将模拟http的结果。请求的ParseForm()函数func parseForm() url.Values {return url.Values{"Name": []string{"joeybloggs"},"Age": []string{"3"},"Gender": []string{"Male"},"Address[0].Name": []string{"26 Here Blvd."},"Address[0].Phone": []string{"9(999)999-9999"},"Address[1].Name": []string{"26 There Blvd."},"Address[1].Phone": []string{"1(111)111-1111"},"active": []string{"true"},"MapExample[key]": []string{"value"},"NestedMap[key][key]": []string{"value"},"NestedArray[0][0]": []string{"value"},}}
编码
package mainimport ("fmt""log""github.com/go-playground/form/v4")// Address contains address information//地址包含地址信息type Address struct {Name stringPhone string}// User contains user information//User包含用户信息type User struct {Name stringAge uint8Gender stringAddress []AddressActive bool `form:"active"`MapExample map[string]stringNestedMap map[string]map[string]stringNestedArray [][]string}// use a single instance of Encoder, it caches struct info//使用单一的编码器实例,它缓存结构信息var encoder *form.Encoderfunc main() {encoder = form.NewEncoder()user := User{Name: "joeybloggs",Age: 3,Gender: "Male",Address: []Address{{Name: "26 Here Blvd.", Phone: "9(999)999-9999"},{Name: "26 There Blvd.", Phone: "1(111)111-1111"},},Active: true,MapExample: map[string]string{"key": "value"},NestedMap: map[string]map[string]string{"key": {"key": "value"}},NestedArray: [][]string{{"value"}},}// must pass a pointervalues, err := encoder.Encode(&user)if err != nil {log.Panic(err)}fmt.Printf("%#v\n", values)}
注册自定义类型
解码器
decoder.RegisterCustomTypeFunc(func(vals []string) (interface{}, error) {return time.Parse("2006-01-02", vals[0])}, time.Time{})
附加:如果注册了一个结构类型,该函数将只在url时被调用。值为结构而存在,而不仅仅是结构字段。url。value {“User”:”Name%3Djoeybloggs”}将调用以’User’为类型的自定义类型函数,但是url.Values{“User.Name”:”joeybloggs”}不会。
编码器
encoder.RegisterCustomTypeFunc(func(x interface{}) ([]string, error) {return []string{x.(time.Time).Format("2006-01-02")}, nil}, time.Time{})
忽略字段
您可以告诉form在标记中使用-忽略字段
type MyStruct struct {Field string `form:"-"`}
忽略空值
您可以告诉form在标签中使用omitempty或FieldName omitempty来省略空字段
type MyStruct struct {Field string `form:",omitempty"`Field2 string `form:"CustomFieldName,omitempty"`}
注意
为了最大化与其他系统的兼容性,编码器试图避免在url中使用数组索引。值,如果可能的话。
例如
// A struct field ofField []string{"1", "2", "3"}// will be output a url.Value as"Field": []string{"1", "2", "3"}and not"Field[0]": []string{"1"}"Field[1]": []string{"2"}"Field[2]": []string{"3"}// however there are times where it is unavoidable, like with pointers// 然而,有些时候这是不可避免的,比如指针i := int(1)Field []*string{nil, nil, &i}// to avoid index 1 and 2 must use index"Field[2]": []string{"1"}
基准测试程序数值
注意:前4个解码中的1分配和B/op实际上是传递它时的结构分配,所以原语实际上是零分配。
go test -run=NONE -bench=. -benchmem=truegoos: darwingoarch: amd64pkg: github.com/go-playground/form/benchmarksBenchmarkSimpleUserDecodeStruct-8 5000000 236 ns/op 64 B/op 1 allocs/opBenchmarkSimpleUserDecodeStructParallel-8 20000000 82.1 ns/op 64 B/op 1 allocs/opBenchmarkSimpleUserEncodeStruct-8 2000000 627 ns/op 485 B/op 10 allocs/opBenchmarkSimpleUserEncodeStructParallel-8 10000000 223 ns/op 485 B/op 10 allocs/opBenchmarkPrimitivesDecodeStructAllPrimitivesTypes-8 2000000 724 ns/op 96 B/op 1 allocs/opBenchmarkPrimitivesDecodeStructAllPrimitivesTypesParallel-8 10000000 246 ns/op 96 B/op 1 allocs/opBenchmarkPrimitivesEncodeStructAllPrimitivesTypes-8 500000 3187 ns/op 2977 B/op 36 allocs/opBenchmarkPrimitivesEncodeStructAllPrimitivesTypesParallel-8 1000000 1106 ns/op 2977 B/op 36 allocs/opBenchmarkComplexArrayDecodeStructAllTypes-8 100000 13748 ns/op 2248 B/op 121 allocs/opBenchmarkComplexArrayDecodeStructAllTypesParallel-8 500000 4313 ns/op 2249 B/op 121 allocs/opBenchmarkComplexArrayEncodeStructAllTypes-8 200000 10758 ns/op 7113 B/op 104 allocs/opBenchmarkComplexArrayEncodeStructAllTypesParallel-8 500000 3532 ns/op 7113 B/op 104 allocs/opBenchmarkComplexMapDecodeStructAllTypes-8 100000 17644 ns/op 5305 B/op 130 allocs/opBenchmarkComplexMapDecodeStructAllTypesParallel-8 300000 5470 ns/op 5308 B/op 130 allocs/opBenchmarkComplexMapEncodeStructAllTypes-8 200000 11155 ns/op 6971 B/op 129 allocs/opBenchmarkComplexMapEncodeStructAllTypesParallel-8 500000 3768 ns/op 6971 B/op 129 allocs/opBenchmarkDecodeNestedStruct-8 500000 2462 ns/op 384 B/op 14 allocs/opBenchmarkDecodeNestedStructParallel-8 2000000 814 ns/op 384 B/op 14 allocs/opBenchmarkEncodeNestedStruct-8 1000000 1483 ns/op 693 B/op 16 allocs/opBenchmarkEncodeNestedStructParallel-8 3000000 525 ns/op 693 B/op 16 allocs/op
竞争对手的基准可以在这里找到
免费软件
下面是一个软件列表,它们使用这个库进行解码。
