golang实现URL参数与Go值双向转换插件库form的使用
Golang实现URL参数与Go值双向转换插件库form的使用
简介
form是一个用于在url.Values和Go值之间进行双向转换的Golang库。它具有以下特性:
- 支持几乎所有类型的map
- 支持编号数组(如
Array[0]
)和普通数组(如Array
) - 切片(slice)会遵循指定的索引位置
- 数组(array)会遵循指定的索引位置
- 仅在必要时创建对象
- 允许注册自定义类型
- 默认使用RFC3339格式处理time.Time
- 支持几乎所有Go类型的编码和解码
安装
使用go get安装:
go get github.com/go-playground/form
然后在代码中导入:
import "github.com/go-playground/form/v4"
使用说明
- 使用
.
分隔字段/结构体(如structfield.field
) - 使用
[index或key]
访问slice/array的索引或map的键(如arrayfield[0]
,mapfield[keyvalue]
)
示例
解码示例
package main
import (
"fmt"
"log"
"net/url"
"github.com/go-playground/form/v4"
)
// 包含地址信息
type Address struct {
Name string
Phone string
}
// 包含用户信息
type User struct {
Name string
Age uint8
Gender string
Address []Address
Active bool `form:"active"`
MapExample map[string]string
NestedMap map[string]map[string]string
NestedArray [][]string
}
// 使用单个Decoder实例,它会缓存结构体信息
var decoder *form.Decoder
func main() {
decoder = form.NewDecoder()
// 模拟http.Request的ParseForm()函数结果
values := parseForm()
var user User
// 必须传递指针
err := decoder.Decode(&user, values)
if err != nil {
log.Panic(err)
}
fmt.Printf("%#v\n", user)
}
// 模拟http.Request的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 main
import (
"fmt"
"log"
"github.com/go-playground/form/v4"
)
// 包含地址信息
type Address struct {
Name string
Phone string
}
// 包含用户信息
type User struct {
Name string
Age uint8
Gender string
Address []Address
Active bool `form:"active"`
MapExample map[string]string
NestedMap map[string]map[string]string
NestedArray [][]string
}
// 使用单个Encoder实例,它会缓存结构体信息
var encoder *form.Encoder
func 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"}},
}
// 必须传递指针
values, 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{})
编码器
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:"-"`
}
Omitempty
可以使用,omitempty
或FieldName,omitempty
标签告诉form忽略空字段:
type MyStruct struct {
Field string `form:",omitempty"`
Field2 string `form:"CustomFieldName,omitempty"`
}
注意事项
为了最大限度地与其他系统兼容,Encoder会尽量避免在url.Values中使用数组索引。
例如:
// 结构体字段
Field []string{"1", "2", "3"}
// 会输出为url.Value
"Field": []string{"1", "2", "3"}
// 而不是
"Field[0]": []string{"1"}
"Field[1]": []string{"2"}
"Field[2]": []string{"3"}
// 但对于指针等特殊情况必须使用索引
i := int(1)
Field []*string{nil, nil, &i}
// 要避免索引1和2必须使用索引
"Field[2]": []string{"1"}
性能基准
go test -run=NONE -bench=. -benchmem=true ./...
goos: darwin
goarch: arm64
pkg: github.com/go-playground/form/v4/benchmarks
BenchmarkSimpleUserDecodeStruct-8 8704111 121.1 ns/op 64 B/op 1 allocs/op
BenchmarkSimpleUserDecodeStructParallel-8 35916134 32.89 ns/op 64 B/op 1 allocs/op
BenchmarkSimpleUserEncodeStruct-8 3746173 320.7 ns/op 485 B/op 10 allocs/op
BenchmarkSimpleUserEncodeStructParallel-8 7293147 180.0 ns/op 485 B/op 10 allocs/op
BenchmarkPrimitivesDecodeStructAllPrimitivesTypes-8 2993259 400.5 ns/op 96 B/op 1 allocs/op
BenchmarkPrimitivesDecodeStructAllPrimitivesTypesParallel-8 13023300 97.70 ns/op 96 B/op 1 allocs/op
BenchmarkPrimitivesEncodeStructAllPrimitivesTypes-8 643202 1767 ns/op 2977 B/op 35 allocs/op
BenchmarkPrimitivesEncodeStructAllPrimitivesTypesParallel-8 1000000 1202 ns/op 2978 B/op 35 allocs/op
BenchmarkComplexArrayDecodeStructAllTypes-8 172630 6822 ns/op 2008 B/op 121 allocs/op
BenchmarkComplexArrayDecodeStructAllTypesParallel-8 719788 1735 ns/op 2009 B/op 121 allocs/op
BenchmarkComplexArrayEncodeStructAllTypes-8 197052 5839 ns/op 7087 B/op 104 allocs/op
BenchmarkComplexArrayEncodeStructAllTypesParallel-8 348039 3247 ns/op 7089 B/op 104 allocs/op
BenchmarkComplexMapDecodeStructAllTypes-8 139246 8550 ns/op 5313 B/op 130 allocs/op
BenchmarkComplexMapDecodeStructAllTypesParallel-8 409018 3143 ns/op 5317 B/op 130 allocs/op
BenchmarkComplexMapEncodeStructAllTypes-8 208833 5515 ns/op 4257 B/op 103 allocs/op
BenchmarkComplexMapEncodeStructAllTypesParallel-8 523833 2182 ns/op 4258 B/op 103 allocs/op
BenchmarkDecodeNestedStruct-8 807690 1408 ns/op 344 B/op 14 allocs/op
BenchmarkDecodeNestedStructParallel-8 3409441 359.6 ns/op 344 B/op 14 allocs/op
BenchmarkEncodeNestedStruct-8 1488520 803.6 ns/op 653 B/op 16 allocs/op
BenchmarkEncodeNestedStructParallel-8 3570204 346.6 ns/op 653 B/op 16 allocs/op
许可证
基于MIT许可证分发,更多详情请参见代码中的许可证文件。
更多关于golang实现URL参数与Go值双向转换插件库form的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复