英文:
More idiomatic way of checking multiple properties of a struct?
问题
假设我有以下结构体:
type myType struct {
Qid, Interval, RoundNumber string
}
我需要确保 myType
类型的变量的属性值不为空字符串。除了使用以下的 if
语句外,是否有更优雅的方式呢?
if aMyType.Qid == "" || aMyType.Interval == "" || aMyType.RoundNumber == "" {
// 处理错误情况
}
显然,使用 if
语句是可行的,但我想知道 Go 语言是否有更好的方式?
英文:
Assume I have the following struct:
type myType struct {
Qid, Interval, RoundNumber string
}
and I have to make sure that a variable of type myType does not have an empty string value for any of the properties.
Is there a more idiomatic way than doing the following if:
if aMyType.Qid == "" || aMyType.Interval == "" || aMyType.RoundNumber == "" {
// handle error situation
}
Obviously the if works but I was wondering whether Go has a better way?
答案1
得分: 8
你可以在myType
上定义一个函数,以便更容易确定其有效性:
func (m myType) Valid() bool {
return m.Qid != "" && m.Interval != "" && m.RoundNumber != ""
}
if aMyType.Valid() {
// ...
}
这段代码定义了一个名为Valid
的方法,它返回一个布尔值,用于判断myType
对象是否有效。在使用时,可以通过调用aMyType.Valid()
来检查对象的有效性。
英文:
You might define a function on myType
that would make it easier to determine validity:
func (m myType) Valid() bool {
return m.Qid != "" && m.Interval != "" && m.RoundNumber != ""
}
And then:
if aMyType.Valid() {
// ...
}
答案2
得分: 1
我不会声称这是惯用语,但如果你想玩弄反射...你可以动态检查结构体中导出的(首字母大写)字段。这个示例检查结构体中所有非空的导出字符串。它不处理嵌套结构体。
type myType struct {
Number int
A, b, C string
}
func (m *myType) IsValid() bool {
v := reflect.ValueOf(*m)
for i := 0; i < v.NumField(); i++ {
sv := v.Field(i)
if sv.Kind() == reflect.String && sv.CanInterface() && sv.Interface() == "" {
return false
}
}
return true
}
func main() {
// false
fmt.Println((&myType{}).IsValid())
// true
fmt.Println((&myType{A: "abc", C: "123"}).IsValid())
}
这段代码通过仅检查导出的字符串类型是否为空来实现。
请注意,这段代码使用了反射,反射是一种强大但复杂的技术,应该谨慎使用。
英文:
I won't claim it's idiomatic, but if you want to play around with reflection... You can dynamically inspect the exported (capital first letter) fields of a struct. This example inspects all of the exported strings in the struct for non-empty. This doesn't handle nested structs.
http://play.golang.org/p/IjMW8OJKlc
type myType struct {
Number int
A, b, C string
}
This works by only checking for empty on exported string types.
func (m *myType) IsValid() bool {
v := reflect.ValueOf(*m)
for i := 0; i < v.NumField(); i++ {
sv := v.Field(i)
if sv.Kind() == reflect.String && sv.CanInterface() && sv.Interface() == "" {
return false
}
}
return true
}
func main() {
// false
fmt.Println((&myType{}).IsValid())
// true
fmt.Println((&myType{A: "abc", C: "123"}).IsValid())
}
答案3
得分: 0
对于你提到的简单情况,我认为你提供的方法在Go语言中更自然、更习惯用法:
if mt.Qid == "" || mt.Interval == "" || mt.RoundNumber == "" {
// 处理错误情况
}
但是,如果你的结构体比较复杂,验证规则也比较复杂,那么使用一个专门的库,比如 validating,可能更符合习惯用法。你可以在这里查看一个稍微复杂一点的用例 here,以及一个非常复杂的用例 here。
作为对比,使用 validating 可以实现你提到的验证规则,代码如下:
import v "github.com/RussellLuo/validating"
errs := v.Validate(v.Schema{
v.F("qid", &mt.Qid): v.Nonzero(),
v.F("interval", &mt.Interval): v.Nonzero(),
v.F("round_number", &mt.RoundNumber): v.Nonzero(),
})
英文:
For simple cases as you mentioned, I think the method you provided is more natural and more idiomatic in Go:
<!-- language: go -->
if mt.Qid == "" || mt.Interval == "" || mt.RoundNumber == "" {
// handle error situation
}
But if your struct is non-trivial and the validation rule is complicated, then it may be more idiomatic to leverage a dedicated library such as validating. See here for a slightly more complex use-case, and here for a very complicated use-case.
As a contrast, by using validating, the validation rule you mentioned can be implemented as follows:
<!-- language: go -->
import v "github.com/RussellLuo/validating"
errs := v.Validate(v.Schema{
v.F("qid", &mt.Qid): v.Nonzero(),
v.F("interval", &mt.Interval): v.Nonzero(),
v.F("round_number", &mt.RoundNumber): v.Nonzero(),
})
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论