我在单元测试中遇到意外行为,它使用reflect.DeepEqual来测试两个已解析结构的相等性。结构包含一片net.IPNet
结构。测试失败,因为reflect.DeepEqual
返回false。
在追踪此问题的同时,我发现了DeepEqual的以下意外行为。对我来说最吸引人的是它可以使用IPv6地址并使用战争解析的IP,而不是net.IPNet
结构中的掩码。
任何人都可以向我解释:
示例程序,可以go run
运行:
package main
import (
"fmt"
"net"
"reflect"
)
func main() {
aip, a, _ := net.ParseCIDR("135.104.0.0/32")
//aip, a, _ := net.ParseCIDR("abcd:2345::/65")
bip := net.IPv4(135, 104, 0, 0)
//bip := net.ParseIP("abcd:2345::")
// IPa: 135.104.0.0 3133352e3130342e302e30
fmt.Printf("IPa: %s %x\n", a.IP, a.IP)
// IPb: 135.104.0.0 3133352e3130342e302e30
fmt.Printf("IPb: %s %x\n", bip, bip)
fmt.Println("eq?:", a.IP.Equal(bip)) // true
// I'd expect this to be true
fmt.Println("deep eq?:", reflect.DeepEqual(a.IP, bip)) // false
fmt.Println("deep eq w/o mask?:", reflect.DeepEqual(aip, bip)) // true
}
答案 0 :(得分:1)
他们并不平等,因为他们不会遇到definition of deep equality。
通过查看每个值的内部表示,正如我on this playground所做的那样,我们可以看到,虽然它们都是IPv4地址,但bip
前面有一些额外的字节(可能是IPv6)代表......为什么,我不确定。
IPa: 135.104.0.0 3133352e3130342e302e30 net.IP net.IP{0x87, 0x68, 0x0, 0x0}
IPb: 135.104.0.0 3133352e3130342e302e30 net.IP net.IP{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x87, 0x68, 0x0, 0x0}
此外,使用DeepEqual比较一些基本的IP地址是一个非常糟糕的想法™,原因很简单,因为IP 不是深层结构。它们(出于平等目的)是简单的不透明值。所以直接比较不透明值。这将意味着从各种存储结构输出一些内容,但以通用格式输出它们并进行比较。比较字节表示中的直接IP(int32
)通常是最有效的。如果您需要比较网络地址,网络掩码等,请以相同的方式进行。或者,比较字符串表示,如果这对您的工具更容易。
但核心是,IP地址只是一个32位整数(在IPv6的情况下是128位整数),其他属性是其他整数。检查整数上的深度等式是没有意义的。