c语言equal,【玩转Golang】reflect.DeepEqual

如果有两个map,内容都一样,只有顺序不同

m1:=map[string]int{"a":1,"b":2,"c":3};

m2:=map[string]int{"a":1,"c":3,"b":2};

我们怎么判断二者是否一致呢?

如果你打算这么写:

fmt.Println("m1==m2",m1==m2)

这是行不通的,go没有重写map的==操作符,编译器会报告错误:

invalid operation: m1 == m2 (map can only be compared to nil)

意思是map的变量只能和空(nil)比较,例如:

fmt.Println("m1 == nil?",m1==nil)

fmt.Println("m2 != nil?",m2!=nil)

这没有问题,执行结果是:

Running...

m1 == nil? false

m2 != nil? true

那怎么比较呢?如果要编程实现,还真是麻烦,比如我的想法是:循环m1,看看每个key是否都在m2中存在,再比较m1[key]是否和m2[key]相等,如果都ok,再依次循环m2。还真是麻烦:

func cmpMap(m1,m2 map[string]int)bool{for k1,v1 :=range m1{if v2,has:=m2[k1];has{if v1!=v2 {return false}

}else{return false;

}

}for k2,v2:=range m2{if v1,has:=m1[k2];has{if v1!=v2{return false;

}

}else{return false;

}

}return true;

}

其实,go的反射包中有一个巨好用的武器reflect.DeepEqual,可以方便解决这个问题,请看:

package main

import("fmt"

"reflect")

type ttstruct{

Codeint}

func main(){

m1:=map[string]int{"a":1,"b":2,"c":3};

m2:=map[string]int{"a":1,"c":3,"b":2};

fmt.Println("m1 == nil?",m1==nil)

fmt.Println("m2 != nil?",m2!=nil)//fmt.Println("m1==m2",m1==m2)

fmt.Println("cmpMap(m1,m2) =",cmpMap(m1,m2));

fmt.Println("reflect.DeepEqual(m1,m2) =",reflect.DeepEqual(m1,m2))

fmt.Println()

m3:=map[string]int{"a":1,"b":2,"c":3,"d":1};

fmt.Println("cmpMap(m1,m3)=",cmpMap(m1,m3));

fmt.Println("reflect.DeepEqual(m1,m3) =",reflect.DeepEqual(m1,m3))

}

func cmpMap(m1,m2 map[string]int)bool{for k1,v1 :=range m1{if v2,has:=m2[k1];has{if v1!=v2 {return false}

}else{return false;

}

}for k2,v2:=range m2{if v1,has:=m1[k2];has{if v1!=v2{return false;

}

}else{return false;

}

}return true;

}

执行结果:

Running...

m1== nil? falsem2!= nil? truecmpMap(m1,m2)= truereflect.DeepEqual(m1,m2)= truecmpMap(m1,m3)= falsereflect.DeepEqual(m1,m3)= falseSuccess: process exited with code0.

但是美中不足的是,由于reflect.DeepEqual需要经过反射操作,效率比我们自己写的函数差的多了,写个简单的测试:

start:=time.Now();

for i:=0;i<100000;i++{

cmpMap(m1,m2)

}

end:=time.Now();

du:=end.Sub(start)

fmt.Println("100000 call cmpMap(m1,m2) elapsed=",du)

start=time.Now();

for i:=0;i<100000;i++{

reflect.DeepEqual(m1,m2);

}

end=time.Now();

du=end.Sub(start);

fmt.Println("100000 call reflect.DeepEqual(m1,m2) elapsed=",du)

看看结果,大约有10倍的差距

100000 call cmpMap(m1,m2) elapsed= 75.544992ms100000 call reflect.DeepEqual(m1,m2) elapsed= 735.577069ms

当然,在一般情况下,这点儿性能损失不算什么,尤其在不确定类型需要反射的时候,更是我们不可不用的强大工具。

比如:

func main(){

m1:=map[string]interface{}{"a":"1", "b":2, "c":3};

m2:=map[string]interface{}{"a":1, "c":"3", "b":2};

fmt.Println(`reflect.DeepEqual(m1["a"],m2["a"]`,reflect.DeepEqual(m1["a"],m2["a"]));

fmt.Println(`reflect.DeepEqual(m1["b"],m2["b"]`,reflect.DeepEqual(m1["b"],m2["b"]));

}

执行结果:

Running...

reflect.DeepEqual(m1["a"],m2["a"] falsereflect.DeepEqual(m1["b"],m2["b"] true

这种情况,如果我们自己写代码比较,势必要使用switch type语法,实在是太麻烦了,感谢go包含了这么好的工具。

有疑问加站长微信联系(非本文作者)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值