在Go语言中,没有反射的情况下,最佳的动态检查模式是什么?

huangapple go评论101阅读模式
英文:

Best patterns for dynamic checks in Go without reflection?

问题

我们的代码库中是否有任何好的模式可以帮助减少对类型字段/结构的冗余检查?我觉得Lisp在处理这些问题上做得很好,但我想了解是否有任何好的模式可以不需要像反射等东西。

例如,对于自定义结构,我发现自己经常需要做很多这样的检查:

  1. type helloworld struct {
  2. field1 *string
  3. field2 *string
  4. field3 int
  5. }
  6. if field1 != nil {
  7. if len([]rune(*field1)) > MAX_ALLOWED_LEN) return errors.New("超过最大允许长度")
  8. }
  9. if field2 != nil {
  10. if len([]rune(*field2)) > MAX_ALLOWED_LEN) return errors.New("超过最大允许长度")
  11. }
  12. if field3 != 0 { //做一些操作}
  13. ....

映射是很好的,但是类型有时太泛化,这也可能导致混淆。我之所以问这个问题,是因为其中一些检查是冗余的,并且在许多包中广泛存在,所以当我需要添加一个额外的字段时,重构是耗时的。如果我可以在某些类型或字段上进行验证,并保持高性能,那将很好。

英文:

Any chance there are good patterns in any of our codebases that help reduce redundant checks on typed fields/structs? I feel like Lisp handles these things well, but trying to understand if there are any good patterns without the need for something like reflection, etc.

For example, for custom structs, I find myself needing to do a lot of:

  1. type helloworld struct {
  2. field1 *string
  3. field2 *string
  4. field3 int
  5. }
  6. if field1 != nil {
  7. if len([]rune(*field1)) > MAX_ALLOWED_LEN) return errors.New("exceeded max allowable length")
  8. }
  9. if field2 != nil {
  10. if len([]rune(*field2)) > MAX_ALLOWED_LEN) return errors.New("exceeded max allowable length")
  11. }
  12. if field3 != 0 { //do stuff}
  13. ....

maps are great, but typing can be too generic a lot of the time, which can also cause confusion. I ask, because some of these checks are redundant and proliferate through a lot of packages, so when I need to add an additional field, refactoring is time consuming. It would be nice if I have validation on certain types or fields while keeping performance high.

答案1

得分: 1

3个方向,不是最直接的,但它们可以减少你的检查块:

方法1:定义自己的注解

Golang在结构体中有注解

  1. type bla struct {
  2. t string `json:"some,omitempty"`
  3. }

这实际上是一个开放的注解结构(标签)。

一个很好的例子(包含一些反射)是https://github.com/mitchellh/mapstructure

看一下mapstructure.go文件的第374行。它非常可重用,你可以将其作为自己注解的基础。

要在你的上下文中使用它,你可以创建类型,然后进行解析。

方法2:DRY检查函数

你的检查似乎是相同或相似的。

一个通用的比较器,遍历字段:

  1. func check(fields ...interface{}) error {
  2. for v := range fields {
  3. if v == nil {
  4. return errors.New("nil")
  5. }
  6. switch v.(type) {
  7. case *string:
  8. if len([]rune(*v)) > MAX_ALLOWED_LEN {
  9. return errors.New("超过最大允许长度")
  10. }
  11. }
  12. ...
  13. }
  14. }

方法3:泛型。

方法2中的switch类型可能可以以泛型风格重写。不容易,但可能更漂亮。

英文:

3 directions, not the most straight forward, but they can reduce your check blocks:

Method 1: Define your own annotation

Golang has annotations in structs

  1. type bla struct {
  2. t string `json:"some,omitempty"`
  3. }

This is actually an open annotation structure (tags).

A nice example (contains some reflection) is https://github.com/mitchellh/mapstructure

Look at line 374 of the mapstructure.go file. It is pretty re-usable, and you could use it as base for your own annotation.

To use it in your context you would create types which you can then parse.

Method 2: DRY check function

Your check seems to be the same or similar.

A generic comparator which iterates over fields:

  1. func check(fields ...interface{}) error {
  2. for v:=range fields {
  3. if v==nil {
  4. return errors.New("nil")
  5. }
  6. switch v.(type) {
  7. case *string:
  8. if len([]rune(*v)) > MAX_ALLOWED_LEN) {
  9. return errors.New("exceeded max allowable length")
  10. }
  11. }
  12. ...
  13. }
  14. }

Method 3: Generics.

The switch type in method 2 might be able to be rewritten in a generic style. Not easier, but can be prettier.

huangapple
  • 本文由 发表于 2022年8月11日 07:25:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/73313745.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定