比较除了一个字段golang之外的结构

Gau*_*shy 4 struct go

我正在比较两个结构,并希望忽略单个字段.

type test struct {
  name string
  time string
} 

func main() {
  a := test{"testName", time.Now().Format(time.UnixTime)}
  // after some time
  b := test{"testName", time.Now().Format(time.UnixTime)}

  fmt.Println(a.Name == b.Name) \\ returns true Desired outcome
  fmt.Println(reflect.DeepEqual(a,b)) \\ returns false

}
Run Code Online (Sandbox Code Playgroud)

reflect.DeepEqual() 不允许我们忽略一个字段并且一次手动完成一个字段的比较.

什么是惯用的方法呢?

Ale*_*nok 11

惯用法是实现自己的func (o MyStruct) Equal(o2 MyStruct) bool方法.

  • 这个答案为问题提供了具体的解决方案 (2认同)

Dav*_*ara 6

出于测试目的,您可以使用cmpoptscmp.Equal - 这允许在使用cmp时忽略(导出的)字段。

func main() {
    a := test{"testName", time.Now().Local().String()}
    // after some time
    b := test{"testName", time.Now().Local().String()}

    fmt.Printf("a: %#v\nb: %#v\n", a, b)

    if !cmp.Equal(a, b, cmpopts.IgnoreFields(test{}, "Time")) {
        log.Fatalf("mismatching data")
    }
}
Run Code Online (Sandbox Code Playgroud)


icz*_*cza 5

1.嵌入

一种选择是将应该参与比较的字段分组为不同的结构,然后将其嵌入到原始结构中。比较时,只需比较嵌入的字段:

type Person struct {
    Name string
    Age  int
}

type Doc struct {
    Person
    Created time.Time
}

func main() {
    d1 := Doc{
        Person:  Person{"Bob", 21},
        Created: time.Now(),
    }
    time.Sleep(time.Millisecond)
    d2 := Doc{
        Person:  Person{"Bob", 21},
        Created: time.Now(),
    }

    fmt.Println(d1 == d2)               // false
    fmt.Println(d1.Person == d2.Person) // true
}
Run Code Online (Sandbox Code Playgroud)

Go Playground上尝试一下。

如果该结构不包含指针,切片,映射等,则可以使用来比较嵌入的值==。否则,使用reflect.DeepEqual()它们进行比较。

2.临时修改可排除字段

您还可以选择临时修改您不想比较的字段:使其相等,因此比较结果将仅取决于其余字段:

a := test{"testName", time.Now().Format(time.StampMilli)}
time.Sleep(time.Millisecond)
b := test{"testName", time.Now().Format(time.StampMilli)}

// Save and make excluded fields equal:
old := a.time
a.time = b.time

fmt.Println(a.name == b.name)        // true
fmt.Println(reflect.DeepEqual(a, b)) // true

// Restore:
a.time = old
Run Code Online (Sandbox Code Playgroud)

Go Playground上尝试一下。

另一个变体是复制一个结构值,然后将其修改并与另一个结构值进行比较,因此无需还原原始结构,这也是“更加并发友好的”:

// Make copies and make excluded fields equal:
a2 := a
a2.time = b.time

fmt.Println(a2.name == b.name)        // true
fmt.Println(reflect.DeepEqual(a2, b)) // true
Run Code Online (Sandbox Code Playgroud)

Go Playground上尝试一下。

3.实施自己的自定义比较

如果您不能使用上述解决方案,可以随时创建自己的解决方案:

func compare(a, b test) bool {
    return a.name == b.name
}


fmt.Println(a.name == b.name) // true
fmt.Println(compare(a, b))    // true
Run Code Online (Sandbox Code Playgroud)

Go Playground上尝试一下。

笔记:

起初这不是“友好的”,因为自定义compare()功能要求您检查所有涉及的字段,但是其实现可能使用上述方法,例如(在Go Playground上尝试):

func compare(a, b test) bool {
    a.time = b.time // We're modifying a copy, so no need to make another copy
    return reflect.DeepEqual(a, b)
}
Run Code Online (Sandbox Code Playgroud)

您还可以传递指向的指针以compare()避免复制原始结构,例如(在Go Playground上尝试):

fmt.Println(a.name == b.name) // true
fmt.Println(compare(&a, &b))  // true

func compare(a, b *test) bool {
    a2 := new(test)
    *a2 = *a
    a2.time = b.time
    return reflect.DeepEqual(a2, b)
}
Run Code Online (Sandbox Code Playgroud)