Skip to content

fix: 通配符规则验证 JSON 反序列化的切片时误判失败#329

Merged
inhere merged 2 commits intogookit:masterfrom
devhaozi:master
Feb 7, 2026
Merged

fix: 通配符规则验证 JSON 反序列化的切片时误判失败#329
inhere merged 2 commits intogookit:masterfrom
devhaozi:master

Conversation

@devhaozi
Copy link

@devhaozi devhaozi commented Feb 6, 2026

Fix #328

问题描述

使用通配符规则(如 Domains.*)验证 slice 中的元素时,如果 slice 是通过 json.Unmarshal 创建的,即使数据完全合法,验证也会错误地失败。

原因分析

validating.go 第 312 行使用 sliceLen < sliceCap 来判断切片是否"元素不足",满足条件时直接跳过逐元素验证,用 nil 调用 required 校验导致失败:

  sliceLen, sliceCap := rftVal.Len(), rftVal.Cap()
  // ...
  if !r.nameNotRequired && sliceLen < sliceCap {
      return callValidator(v, fm, field, nil, r.arguments, addNum)
  }

但在 Go 中,cap > len 是完全正常的行为。json.Unmarshal、append 等标准操作在扩容时会分配额外容量:

// 直接构造:len=3, cap=3
s := []string{"a", "b", "c"}

// json.Unmarshal:len=3, cap=4
var s []string
json.Unmarshal([]byte(`["a","b","c"]`), &s)

3 个元素的切片经 JSON 解码后 cap=4,导致 len(3) < cap(4) 为 true,验证器跳过了正常的逐元素检查,直接返回 required 错误。

修复方式

将 sliceLen < sliceCap 改为 sliceLen == 0。这个检查的本意是在 slice 没有任何元素时让 required 验证失败,正确的条件就是 len == 0。

复现方式

  type Test struct {
      Domains []string `json:"domains" validate:"required|isSlice"`
  }

  data := `{"domains":["example.com","test.com","a.com"]}`
  req := new(Test)
  json.Unmarshal([]byte(data), req)

  df, _ := validate.FromStruct(req)
  v := df.Create()
  v.StringRule("Domains.*", "required")

  // 修复前:v.Validate() == false(错误)
  // 修复后:v.Validate() == true(正确)

@devhaozi
Copy link
Author

devhaozi commented Feb 6, 2026

测试失败似乎是之前提交导致的问题,与此PR无关。

@inhere
Copy link
Member

inhere commented Feb 7, 2026

测试失败似乎是之前提交导致的问题,与此PR无关。

好的,我稍后修复下测试

@inhere inhere merged commit dc32dc1 into gookit:master Feb 7, 2026
4 of 11 checks passed
@inhere inhere added the bug_fix label Feb 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

json Unmarshal 的切片无法正确使用 required 验证器验证

3 participants