英文:
Best patterns for dynamic checks in Go without reflection?
问题
我们的代码库中是否有任何好的模式可以帮助减少对类型字段/结构的冗余检查?我觉得Lisp在处理这些问题上做得很好,但我想了解是否有任何好的模式可以不需要像反射等东西。
例如,对于自定义结构,我发现自己经常需要做很多这样的检查:
type helloworld struct {
field1 *string
field2 *string
field3 int
}
if field1 != nil {
if len([]rune(*field1)) > MAX_ALLOWED_LEN) return errors.New("超过最大允许长度")
}
if field2 != nil {
if len([]rune(*field2)) > MAX_ALLOWED_LEN) return errors.New("超过最大允许长度")
}
if field3 != 0 { //做一些操作}
....
映射是很好的,但是类型有时太泛化,这也可能导致混淆。我之所以问这个问题,是因为其中一些检查是冗余的,并且在许多包中广泛存在,所以当我需要添加一个额外的字段时,重构是耗时的。如果我可以在某些类型或字段上进行验证,并保持高性能,那将很好。
英文:
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:
type helloworld struct {
field1 *string
field2 *string
field3 int
}
if field1 != nil {
if len([]rune(*field1)) > MAX_ALLOWED_LEN) return errors.New("exceeded max allowable length")
}
if field2 != nil {
if len([]rune(*field2)) > MAX_ALLOWED_LEN) return errors.New("exceeded max allowable length")
}
if field3 != 0 { //do stuff}
....
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在结构体中有注解
type bla struct {
t string `json:"some,omitempty"`
}
这实际上是一个开放的注解结构(标签)。
一个很好的例子(包含一些反射)是https://github.com/mitchellh/mapstructure
看一下mapstructure.go文件的第374行。它非常可重用,你可以将其作为自己注解的基础。
要在你的上下文中使用它,你可以创建类型,然后进行解析。
方法2:DRY检查函数
你的检查似乎是相同或相似的。
一个通用的比较器,遍历字段:
func check(fields ...interface{}) error {
for v := range fields {
if v == nil {
return errors.New("nil")
}
switch v.(type) {
case *string:
if len([]rune(*v)) > MAX_ALLOWED_LEN {
return errors.New("超过最大允许长度")
}
}
...
}
}
方法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
type bla struct {
t string `json:"some,omitempty"`
}
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:
func check(fields ...interface{}) error {
for v:=range fields {
if v==nil {
return errors.New("nil")
}
switch v.(type) {
case *string:
if len([]rune(*v)) > MAX_ALLOWED_LEN) {
return errors.New("exceeded max allowable length")
}
}
...
}
}
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论