检查结构体的多个属性的更习惯用法是什么?

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

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 &lt; v.NumField(); i++ {
		sv := v.Field(i)
		if sv.Kind() == reflect.String &amp;&amp; sv.CanInterface() &amp;&amp; sv.Interface() == &quot;&quot; {
			return false
		}
	}
	return true
}

func main() {
	// false
	fmt.Println((&amp;myType{}).IsValid())
	// true
	fmt.Println((&amp;myType{A: &quot;abc&quot;, C: &quot;123&quot;}).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 == &quot;&quot; || mt.Interval == &quot;&quot; || mt.RoundNumber == &quot;&quot; {
    // 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 &quot;github.com/RussellLuo/validating&quot;

errs := v.Validate(v.Schema{
    v.F(&quot;qid&quot;, &amp;mt.Qid):                  v.Nonzero(),
    v.F(&quot;interval&quot;, &amp;mt.Interval):        v.Nonzero(),
    v.F(&quot;round_number&quot;, &amp;mt.RoundNumber): v.Nonzero(),
})

huangapple
  • 本文由 发表于 2014年2月28日 23:18:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/22098974.html
匿名

发表评论

匿名网友

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

确定