英文:
IP-Part of net.IPNet does not fulfil reflect.DeepEqual, but are Equal
问题
我正在经历一个单元测试中的意外行为,该测试使用reflect.DeepEqual
来测试两个解析结构的相等性。这些结构包含一个net.IPNet
结构的切片。测试失败是因为reflect.DeepEqual
返回false。
在追踪此问题时,我发现了DeepEqual
的以下意外行为。对我来说最有趣的是它可以处理IPv6地址,并且使用解析后的IP,而不是net.IPNet
结构中的掩码IP。
有人能解释一下:
- 为什么这些IPv4地址不相等,尽管它们的字节表示似乎相等?
- 为什么IPv6地址相等?
- 如何构造一个与使用ParseCIDR生成的net.IP实例相匹配的实例,以满足DeepEqual的要求?
以下是可用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
}
希望对你有所帮助!
英文:
I'm experiencing unexpected behavior in a unit test which uses reflect.DeepEqual to test for the equality of two parsed structures. The structures contain a Slice of net.IPNet
structs. The tests fail because reflect.DeepEqual
returns false.
While tracking this issue down I found the following unexpected behavior of DeepEqual. The most fascinating thing for me is that it works with IPv6 addresses and using the war parsed IP, not the masked one in the net.IPNet
struct.
Can anyone explain to me:
- Why are those IPv4 addresses not DeepEqual, despite their byte-representation seems to be?
- Why are they DeepEqual for IPv6 addresses?
- How to construct an net.IP instance that match the one generated by ParseCIDR with respect to DeepEqual?
Example program, runable with 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
}
答案1
得分: 1
它们不是深度相等的,因为它们不符合深度相等的定义。
通过查看每个值的内部表示,就像我在这个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地址对于相等目的来说是简单的不透明值。所以直接比较这些不透明值。这意味着从各种存储结构中输出一些内容,但以一种通用的格式输出它们并进行比较。直接比较字节表示(int32
)的IP地址通常是最高效的。如果需要比较网络地址、子网掩码等,请以相同的方式进行。或者,如果对于你的工具来说更容易,可以比较字符串表示。
但在核心,IP地址只是一个32位整数(对于IPv6来说是128位整数),其他属性是其他整数。对整数进行深度相等性检查是没有意义的。
英文:
They aren't deep equal because they don't meet the definition of deep equality.
By looking at the internal representation of each value, as I did on this playground, we can see that while they are both IPv4 address, bip
is preceded by a number of extra bytes (presumably the IPv6 representation... why, I'm not sure).
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}
Further, using DeepEqual to compare something as basic as an IP address is a Very Bad Idea™, for the simple reason that IPs are not deep structures. They are (for equality purposes) simple opaque values. So just compare the opaque values directly. This will mean outputting something from your various storage structs, but output them in a common format and compare that. Comparing straight IPs in their byte representation (int32
) will generally be the most efficient. If you need to compare the network address, netmask, etc, do it the same way. Alternately, compare a string representation, if that's easier for your tools.
But at the core, an IP address is just a 32-bit integer (or 128-bit integer in the case of IPv6), and the other attributes are other integers. Checking for Deep Equality on integers makes no sense.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论