一、结构体的比较
Java 同类型对象之间的比较
以 Java 为例,Java 中的自定义对象是通过实现 equals 方法来定义两个对象之间比较的规则(同一个的两个实例化对象)
public class TestEquals {
public static void main(String[] args) {
Car c1 = new Car();
c1.carNo = "00001";
c1.name = "Model 3";
Car c2 = new Car();
c2.carNo = "00001";
c2.name = "Model 3";
System.out.println(c1.equals(c2));
}
}
class Car {
public String carNo;
public String name;
// 定义比较规则
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
// 转化为同一类型
Car car = (Car) o;
if (!carNo.equals(car.carNo)) return false;
return name.equals(car.name);
}
@Override
public int hashCode() {
int result = carNo.hashCode();
result = 31 * result + name.hashCode();
return result;
}
}
执行 main 方法,输出结果如下:
true
如果比较使用的是 == 则输出结果为 false, == 比较的是内存地址;而 equals 比较时如果重写了 equals 方法就是用 equals 方法中定义的比较规则,如果没有重写则默认使用 object 中的 equals 方法,既比较地址。
Go 同结构体对象之间的比较
Go 语言中是没有类的概念的,Go 语言中的 结构体 的作用就类似其他编译型面向对象语言中的 类 的作用。
结构体之间可以比较吗?
结构体之间可以比较 定义一个 Car 结构体,结构体属性中只包含基本数据类型(值类型,数组除外),并实例化 3 个对象出来
func main(){
c1 := Car{
CarNo: "00001",
Name: "TESLA",
}
c2 := Car{
CarNo: "00001",
Name: "TESLA",
}
c3 := Car{
CarNo: "00001",
Name: "F-Type",
}
fmt.Println(c1 == c2)
fmt.Println(c1 == c3)
}
type Car struct {
CarNo string
Name string
}
执行 main 函数,输出结果如下:
true
false
c1 和 c2 的属性值都是相同的,直接比较输出结果为 true,c1 和 c3 的属性值不同,输出结果为 false。
在 Java 重写 equals 方法的时候会有一个对象类型转换的过程,在 Go 中如果结构体类型不同,但是属性字段和属性值相同也是可以比较的。
新增一个结构体 Truck,字段与 Car 相同,将 c2 实例化改为 Truck,再进行比较,此时编译器报错。
因此需要进行类型转换
// 其余代码不变
fmt.Println(c1 == Car(c2))
再次执行 main 函数,输出结果如下:
true
false
即使是不同的结构体,只要字段相同,且字段是基本的值类型(数组除外)都是可以进行比较的。
如果结构体字段包含了引用输入类型可以比较吗?
给 Car 结构体增加一个指针类型的字段
type Car struct {
CarNo string
Name string
Battery *string
}
定义两个指针变量并实例化 c1 和 c2
b1 := "75KW"
b2 := "75KW"
c1 := Car{
CarNo: "00001",
Name: "TESLA",
Battery: &b1,
}
c2 := Car{
CarNo: "00001",
Name: "TESLA",
Battery: &b2,
}
对 c1 和 c2 进行比较,输出结果为 false, 这是因为两个结构体之间的字段的地址不同。
结构体之间不可以比较 如果结构体的字段包含了数组或者切片,即是内容相同,也是不可以比较的。
修改 Car 结构体
type Car struct {
CarNo string
Name string
Features [2]string
}
修改 Car 结构体的实例化对象
c1 := Car{
CarNo: "00001",
Name: "TESLA",
Features: [2]string{"安全", "舒适"},
}
c2 := Car{
CarNo: "00001",
Name: "TESLA",
Features: [2]string{"安全", "舒适"},
}
再次对 c1 和 c2 进行比较,控制台报错如下:
# command-line-arguments
./ex12.go:14:13: cannot use []string{…} (value of type []string) as type [2]string in struct literal
总结
Go 中当结构体包含了 切片、数组、字典、函数这几种数据类型时,是不能比较的,执行比较会报错。如果需要进行比较,则不能使用 == 进行比较,需要使用 reflect.DeepEqual 方法,用于判断两个值深度是否一致:
- 首先会判断类型,相同类型的值是深度相等的,不同类型的值永远不会深度相等。
- 如果数组值(array)的对应元素深度相等时,数组值是深度相等的,否则不相等。
- 如果结构体(struct)值如果其对应的字段(包括导出和未导出的字段)都是深度相等的,则深度是相等的,否则不相等
- 如果函数(func)值如果都是零,则是深度相等;否则就不相等。
- 如果接口(interface)值持有深度相等的具体值,则深度相等,否则相等。