如何解决通过interface{}传递的对象未初始化字段的问题?

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

How to resolve whether pass objects via interface{} have not initializated fields

问题

我有一个问题,我想确定作为接口传递给函数的对象是否未初始化字段,就像只定义为someObject{}的对象一样,它是空的,因为所有字段的值都为0或nil。

如果我传递不同的对象,问题就变得更加复杂,因为每个对象都有不同类型的字段值,所以目前我找不到通用的方法来解决这个问题。

示例:

func main(){
    oo := objectOne{}
    ot := objectTwo{}
    oth := objectThree{"blah", "balbal", "blaal"}
    resolveIsNotInitialized(oo)
    resolveIsNotInitialized(ot)
    resolveIsNotInitialized(oth)
}

func resolveIsNotInitialized(v interface{}) bool{
    // 在下面,如何解决oo和ot为空的问题
    if (v.SomeMethodWhichCanResolveThatAllFieldsIsNotInitialized){
        return true
    }
    return false
}

我想避免使用像下面这样的switch语句,以及为每个对象编写额外的函数,如果可能的话。

func unsmartMethod(v interface{}) bool{
    switch v.(type){
    case objectOne:
        if v == (objectOne{}) {
          return true
        }
        // 下一个对象,以此类推...
    }
    return false
}
英文:

I have problem with resolve whether object which was pass as interface to function hasn't initializated fields, like object which was defined as just someObject{} is a empty, because all fields, has value 0, or nil

Problem becomes more complicated if I pass diffrent objects, because each object have diffrent type field value so on this moment I don't find universal way to this.

Example

func main(){
	oo := objectOne{}
	ot := objectTwo{}
	oth := objectThree{"blah" , "balbal" , "blaal"}
	resolveIsNotIntialized(oo)
	resolveIsNotIntialized(ot)
	resolveIsNotIntialized(oth)
}

func resolveIsNotIntialized(v interface{}) bool{
	// and below, how resolve that oo and ot is empty
	if (v.SomeMethodWhichCanResolveThatAllFiledIsNotIntialized){
		return true
	}
	return false
}

I want to avoid usage switch statement like below, and additional function for each object, ofcorse if is possible.

func unsmartMethod(v interface{}) bool{
	switch v.(type){
	case objectOne:
		if v == (objectOne{}) {
		  return true
		}
		// and next object, and next....
	}
	return false
}

答案1

得分: 6

正如Franck所指出的,这可能是一个不好的主意。在Go语言中,每个值都会被初始化。你实际上的问题是类型是否等于它的零值。通常,零值应该被设计成有效的。更好的方法通常是创建一个接口,如下所示:

type ZeroChecker interface {
    IsZero() bool
}

然后将其附加到您想要检查的任何类型上。(或者可能更好的是,创建一个IsValid()测试,而不是反向执行逻辑。)

也可以使用反射来检查这一点,通过将其与其零值进行比较。

func resolveIsNotIntialized(v interface{}) bool {
    t := reflect.TypeOf(v)
    z := reflect.Zero(t).Interface()
    return reflect.DeepEqual(v, z)
}

(在这里,你可能可以使用return v == z;我还没有考虑所有可能的情况。)

英文:

As Franck notes, this is likely a bad idea. Every value is always initialized in Go. Your actual question is whether the type equals its Zero value. Generally the Zero value should be designed such that it is valid. The better approach would generally be to create an interface along the lines of:

type ZeroChecker interface {
    IsZero() bool
}

And then attach that to whatever types you want to check. (Or possibly better: create an IsValid() test instead rather than doing your logic backwards.)

That said, it is possible to check this with reflection, by comparing it to its Zero.

func resolveIsNotIntialized(v interface{}) bool {
	t := reflect.TypeOf(v)
	z := reflect.Zero(t).Interface()
	return reflect.DeepEqual(v, z)
}

(You might be able to get away with return v == z here; I haven't thought through all the possible cases.)

答案2

得分: 1

我认为在习惯用语的Go语言中,没有一个好的理由来做你试图做的事情。你需要设计你的结构体,使得默认值(nil、空字符串、0、false等)是有效的,并代表对象的初始状态。看看标准库的源代码,那里有很多这样的例子。
你所建议的可以通过反射轻松实现,但这样做会很慢且笨重。

英文:

I don’t think there is a good reason (in idiomatic Go) to do what you are trying to do. You need to design your structs so that default values (nil, empty string, 0, false, etc.) are valid and represent the initial state of your object. Look at the source of the standard library, there are lots of examples of that.
<br>What you are suggesting is easily doable via Reflection but it will be slow and clunky.

答案3

得分: 1

你可以将函数接受的参数类型进行细化,不要使用interface{},而是接受一个允许你检查非零值的类型,比如在下面的示例代码中使用type intercae{nonZero() bool}。这样做不能明确告诉你它是否被设置为零值,但可以告诉你它不是零。

type nonZeroed interface {
    nonZero() bool
}

type zero struct {
    hasVals bool
}

func (z zero) nonZero() bool {
    return z.hasVals
}

type nonZero struct {
    val int
}

func (nz nonZero) nonZero() bool {
    return nz.val != 0
}

type alsoZero float64

func (az alsoZero) nonZero() bool {
    return az != 0.0
}

func main() {
    z := zero{}
    nz := nonZero{
        val: 1,
    }
    var az alsoZero
    fmt.Println("z has values:", initialized(z))
    fmt.Println("nz has values:", initialized(nz))
    fmt.Println("az has values:", initialized(az))
}

func initialized(a nonZeroed) bool {
    return a.nonZero()
}

显然,随着类型变得更加复杂,需要进行额外的验证来确保它是"非零"的。这种模式可以用来检查任何条件。

英文:

You could narrow the type which your function takes as an argement a little, not take an interface{} but accept one that allows you to check for non-zero values, say type intercae{nonZero() bool} as in the example code below. This will not tell you explicitly that it hasn't been set to the zero value, but that it is not zero.

type nonZeroed interface {
	nonZero() bool
}

type zero struct {
	hasVals bool
}

func (z zero) nonZero() bool {
	return z.hasVals
}

type nonZero struct {
	val int
}

func (nz nonZero) nonZero() bool {
	return nz.val != 0
}

type alsoZero float64

func (az alsoZero) nonZero() bool {
	return az != 0.0
}

func main() {
	z := zero{}
	nz := nonZero{
		val: 1,
	}
	var az alsoZero
	fmt.Println(&quot;z has values:&quot;, initialized(z))
	fmt.Println(&quot;nz has values:&quot;, initialized(nz))
	fmt.Println(&quot;az has values:&quot;, initialized(az))
}

func initialized(a nonZeroed) bool {
	return a.nonZero()
}

Obviously as the type get more complex additional verification would need to be made that it was "nonZero". This type of pattern could be used to check any sort condition.

huangapple
  • 本文由 发表于 2017年1月6日 21:26:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/41506763.html
匿名

发表评论

匿名网友

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

确定