《Go编程语言规范Specification》中提到:
如果结构体的所有字段都是可比较的,则结构体值也是可比较的。如果两个结构体值对应的非空字段相等,则这两个结构体值相等。
但是根据下面的代码片段,变量v1和v3看起来类型不同,为什么它们可以得到true输出:
package main
import "fmt"
import "reflect"
type T1 struct { name string }
type T2 struct { name string }
func main() {
v1 := T1 { "foo" }
v2 := T2 { "foo" }
v3 := struct{ name string } {"foo"}
v4 := struct{ name string } {"foo"}
fmt.Println("v1: type=", reflect.TypeOf(v1), "value=", reflect.ValueOf(v1)) // v1: type= main.T1 value= {foo}
fmt.Println("v2: type=", reflect.TypeOf(v2), "value=", reflect.ValueOf(v2)) // v2: type= main.T2 value= {foo}
fmt.Println("v3: type=", reflect.TypeOf(v3), "value=", reflect.ValueOf(v3)) // v3: type= struct { name string } value= {foo}
fmt.Println("v4: type=", reflect.TypeOf(v4), "value=", reflect.ValueOf(v4)) // v4: type= struct { name string } value= {foo}
//fmt.Println(v1 == v2) // compiler error: invalid operation: v1 == v2 (mismatched types T1 and T2)
fmt.Println(v1 == v3) // true, why? their type is different
fmt.Println(v2 == v3) // true, why?
fmt.Println(v3 == v4) // true
}
合理的是,
v1 == v2
会因为它们是不同类型而导致编译错误,然而如何解释 v1 == v3
得到了一个 true
的结果呢?因为它们也有不同的类型,一个是带有命名结构体类型 T1
,另一个是匿名结构体。感谢 @icza、@John Weldon 的解释,我认为这个问题已经解决了,现在我正在更新问题。
总之,如果一个结构体满足以下两个规范,则可以进行比较:
第一个规范是针对结构体类型变量的具体定义;第二个规范是针对所有类型变量的比较,当然也包括结构体类型变量。
如果所有字段都是可比较的,则结构体值是可比较的。如果它们对应的非空字段相等,则两个结构体值相等。
在任何比较中,第一个操作数必须可分配给第二个操作数的类型,反之亦然。
在我的示例中,比较变量 v1 和 v3 符合这两个规范的定义。
- 所有字段都是可比较的;事实上,第一个规范定义了结构体规则,它关注的是字段,而不是结构体本身,因此无论是命名结构体还是匿名结构体,它们都遵循同样的规则。
- 变量v1和v3是可赋值的。(根据规则:x的类型V和T具有相同的基础类型,并且V或T中至少有一个不是已定义的类型)
这就是为什么"v1 == v3"能得到真结果的原因。