ネスト構造体とスライス
Check はフィールドツリー全体を自動的に走査します。ネストされた データをバリデートするのに opt-in も特別な呼び出しも要りません。
普通のネスト構造体
すべての公開フィールドが再帰的に訪問され、トップレベルと同じよう にタグが発火します:
go
type Address struct {
Street string `valid:"required" label:"街道"`
Zip string `valid:"required;alphanumeric" label:"邮编"`
}
type Profile struct {
Name string `valid:"required" label:"姓名"`
Address Address // タグ不要——内部のフィールドはそれでもバリデートされる
}構造体のスライス
各要素は独立してバリデートされます。エラーは宣言順、続いて要素順で 返ります:
go
type Item struct {
SKU string `valid:"required" label:"SKU"`
Qty int `valid:"min:1" label:"数量"`
}
type Order struct {
Items []Item `valid:"required" label:"商品"`
}
errs, _ := govalid.Check(Order{
Items: []Item{
{SKU: "A1", Qty: 5},
{SKU: "", Qty: 0},
},
})
// errs[0]: "SKU不能为空" (要素 1 から)
// errs[1]: "数量应大于1" (要素 1 から)外側フィールドの required ルールも依然として適用されるため、空の Items: nil スライスは独自の "购物车不能为空" 系エラーを返します。
埋め込み(匿名)構造体
埋め込み構造体は名前付きフィールドと同じように走査されます。埋め 込み型自体が 非公開 であっても動きます——バリデーターは親の Interface() 呼び出しでパニックすることなく、その型の公開フィー ルドへ降下します:
go
type embeddedBase struct {
Name string `valid:"required" label:"姓名"`
}
type Form struct {
embeddedBase
Other string `valid:"required" label:"其他"`
}
errs, _ := govalid.Check(Form{})
// errs[0]: "姓名不能为空"
// errs[1]: "其他不能为空"構造体へのポインタ
ポインタフィールドは自動的に解参照されます。nil ポインタは安全で ——required から Cfg不能为空 を得る形で、パニックにはなりません:
go
type Config struct {
Host string `valid:"required" label:"主机"`
}
type Service struct {
Cfg *Config `valid:"required" label:"配置"`
}構造体ポインタのスライス
[]*T(ポインタスライス)は今日のところ要素ごとに再帰されません ——外側スライスのルールしか発火しません。要素ごとのバリデーション が要るなら []T を使うか、手動でループしてください:
go
for i, item := range pointers {
if errs, ok := govalid.Check(item); !ok {
// ...
}
}トップレベルスライスのバリデーション
Check はトップレベルでも構造体のスライスを受け付けます。すべての 要素がバリデートされます:
go
items := []Item{{SKU: "A1", Qty: 1}, {SKU: "", Qty: 0}}
errs, ok := govalid.Check(items)map と channel のバリデーション
「バリデート可能なコンテナ」と見なされるのは構造体と構造体スライス だけです。トップレベルの map・channel・プリミティブは (nil, true) を返します——バリデーターは黙って通します。構造体な map の 値 をバリデートしたい場合は手動で回します:
go
for _, v := range users {
if errs, ok := govalid.Check(v); !ok {
// ...
}
}