Skip to content

ネスト構造体とスライス

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 {
        // ...
    }
}

MIT ライセンスのもとで公開されています。