我可以为结构体中的字符串字段设置默认最大长度吗?

问题描述 投票:0回答:5

我的应用程序中有多个使用 golang 的结构。结构体中的某些字段具有 maxsize 标签,有些则没有。 例如:

type structone struct {
  fieldone string `valid:MaxSize(2)`
  fieldtwo string 
}

type structtwo struct {
  fieldone string `valid:MaxSize(2)`
  fieldtwo string 
}

所以我想为所有字段设置默认的最大大小,如果在运行时不包含任何有效的最大大小标签。是否可以?有人可以帮忙吗。

validation go struct reflection max-size
5个回答
4
投票

我可以为结构体中的字符串字段设置默认最大长度吗?

没有。


2
投票

string
预声明类型不允许您限制它可能保存的
string
值的长度。

你可以做的是使用一个未导出的字段,这样它就不能在你的包之外被访问(设置),并提供一个setter方法来检查长度,如果它不符合你的要求(或上限),则拒绝设置它值到允许的最大值)。

例如:

func (s *structone) SetFieldone(v string) error {
    if len(v) > 2 {
        return errors.New("too long")
    }
    s.fieldone = v
    return nil
}

0
投票

其他答案似乎假设您在 Go 中使用普通字符串并询问您是否可以限制它们的最大大小。通过提出的一些建议可以实现这一目标。

但是,从您提供的代码片段中,我推断您是在询问 validate go package 是否可以使用标签指定结构中所有字段的默认最大大小。

不幸的是,该库当前不支持为所有字段指定默认验证标签。您必须为结构体的所有字段显式定义验证标记。

您想要实现的目标是可能的,但是库需要扩展。

一个建议是将其扩展以支持语法,例如:

type MyStruct struct {
    valid.Default `valid:MaxSize(5)`

    field1 string
    field2 string
}

0
投票

该程序读取自身,将标签

valid:MaxSize(2)
添加到属性
structone.fieldone
,然后将更新的程序打印到
os.Stdout

package main

import (
    "go/ast"
    "go/printer"
    "go/token"
    "log"
    "os"
    "strings"

    "golang.org/x/tools/go/ast/astutil"
    "golang.org/x/tools/go/loader"
)

type structone struct {
    fieldone string
    fieldtwo string
}

func main() {
    var conf loader.Config
    _, err := conf.FromArgs([]string{"."}, false)
    if err != nil {
        log.Fatal(err)
    }
    prog, err := conf.Load()
    if err != nil {
        log.Fatal(err)
    }
    astutil.Apply(prog.InitialPackages()[0].Files[0], addTag("structone.fieldone", "`valid:MaxSize(2)`"), nil)

    printer.Fprint(os.Stdout, prog.Fset, prog.InitialPackages()[0].Files[0])
}

func addTag(p string, tag string) func(*astutil.Cursor) bool {
    pp := strings.Split(p, ".")
    sName := pp[0]
    pName := pp[1]
    return func(cursor *astutil.Cursor) bool {
        n := cursor.Node()
        if x, ok := n.(*ast.TypeSpec); ok {
            return x.Name.Name == sName
        } else if x, ok := n.(*ast.Field); ok {
            for _, v := range x.Names {
                if v.Name == pName {
                    x.Tag = &ast.BasicLit{
                        Value: tag,
                        Kind:  token.STRING,
                    }
                }
            }
        } else if _, ok := n.(*ast.File); ok {
            return true
        } else if _, ok := n.(*ast.GenDecl); ok {
            return true
        } else if _, ok := n.(*ast.TypeSpec); ok {
            return true
        } else if _, ok := n.(*ast.StructType); ok {
            return true
        } else if _, ok := n.(*ast.FieldList); ok {
            return true
        }
        return false
    }
}

0
投票

这个问题有点老了,但我相信帮助处于同样情况的其他人是值得的。 正如前面的答案之一所示,您将需要“验证器”包并对结构进行一些调整才能实现这一目标。

package main

import (
    "fmt"

    "github.com/go-playground/validator/v10"
)

type Structone struct {
    Fieldone string `validate:"required,lt=10"`
    Fieldtwo string `validate:"required,gte=8"`
}

var validate *validator.Validate

func main() {
    s1 := &Structone{
        Fieldone: "ok string",
        Fieldtwo: "Error!",
    }
    validate = validator.New()
    err := validate.Struct(s1)
    if err != nil {
        // get all error at once
        errs := err.(validator.ValidationErrors)
        fmt.Println(errs)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.