Copy net.IP in Golang

huangapple go评论76阅读模式
英文:

Copy net.IP in Golang

问题

我尝试复制一个net.IP实例的值(第14行和第19行),但显然只是传递了指针。我做错了什么?

请求的代码如下:

package main

import (
	"log"
	"net"
)

type Range struct {
	Start net.IP `json:"start"`
	End   net.IP `json:"end"`
}

func (r Range) Expand() []net.IP {
	next := r.Start // 这里(第14行)
	out := []net.IP{next}

	for !next.Equal(r.End) {
		incIP(next)
		out = append(out, next) // 这里(第19行)
	}

	return out
}

func incIP(ip net.IP) {
	for j := len(ip) - 1; j >= 0; j-- {
		ip[j]++
		if ip[j] > 0 {
			break
		}
	}
}

func main() {
	r := Range{
		Start: net.ParseIP("192.100.10.4"),
		End:   net.ParseIP("192.100.13.1"),
	}
	out := r.Expand()
	log.Print(r)
	log.Print(out)
}

你在代码中的问题是,你传递的是指针而不是值。在Go语言中,net.IP是一个切片类型,它是一个引用类型。当你将一个切片传递给函数时,实际上传递的是切片的指针,而不是切片的副本。因此,在你的代码中,你修改的是原始切片,而不是副本。

要解决这个问题,你可以在Expand函数中创建一个新的net.IP实例,并将原始的net.IP值复制到新的实例中。这样,你就可以修改新的实例而不会影响原始的net.IP值。

以下是修改后的代码:

func (r Range) Expand() []net.IP {
	next := net.IP(r.Start.To4()) // 创建新的net.IP实例并复制值
	out := []net.IP{next}

	for !next.Equal(r.End) {
		incIP(next)
		out = append(out, net.IP(next.To4())) // 创建新的net.IP实例并复制值
	}

	return out
}

通过使用net.IP.To4()方法,你可以创建一个新的net.IP实例并复制原始值。这样,你就可以在循环中修改新的实例,并将其添加到输出切片中,而不会影响原始的net.IP值。

希望这可以帮助到你!

英文:

I try to copy the value of a net.IP instance (line 14 and 19) but obviously just pass around the pointer:

http://play.golang.org/p/xmYQrsf496

What am I doing wrong?

CODE as requested:

package main

import (
	"log"
	"net"
)

type Range struct {
	Start net.IP `json:"start"`
	End   net.IP `json:"end"`
}

func (r Range) Expand() []net.IP {
	next := r.Start // here (line 14)
	out := []net.IP{next}

	for !next.Equal(r.End) {
		incIP(next)
		out = append(out, next) // and here (line 19)
	}

	return out
}

func incIP(ip net.IP) {
	for j := len(ip) - 1; j >= 0; j-- {
		ip[j]++
		if ip[j] > 0 {
			break
    	}
	}
}

func main() {
	r := Range{
		Start: net.ParseIP("192.100.10.4"),
		End:   net.ParseIP("192.100.13.1"),
	}
	out := r.Expand()
	log.Print(r)
	log.Print(out)
}

答案1

得分: 6

看一下net.IP的文档;它只是一个[]byte,所以你可以使用copy内置函数

例如:

func dupIP(ip net.IP) net.IP {
    dup := make(net.IP, len(ip))
    copy(dup, ip)
    return dup
}

如果你关心空间,你还可以从文档中注意到,尽管所有的net例程都支持长度为4的net.IP(例如ip := net.IP([]byte{1, 2, 3, 4})可以工作),但它们生成的所有例程都是16字节。由于你要创建很多个,如果你关心几个字节的空间,或者如果你关心255.255.255.255之后会发生什么,你可以像下面这样避免这个问题:

func dupIP(ip net.IP) net.IP {
    // 为了节省空间,尽量只使用4个字节
    if x := ip.To4(); x != nil {
        ip = x
    }
    dup := make(net.IP, len(ip))
    copy(dup, ip)
    return dup
}

对于IPv6地址,你可能希望做一些不同的处理,我认为按照你的方式对IPv6进行“递增”可能没有意义,不过我可能错了。

你可以在这里找到修改后的原始版本:https://play.golang.org/p/GP9vASvUgh

英文:

Look at the documentation for net.IP; it's just a []byte so you could use the copy builtin.

E.g.:

func dupIP(ip net.IP) net.IP {
    dup := make(net.IP, len(ip))
    copy(dup, ip)
    return dup
}

If you care about space, you can also note from the documentation that although all the net routines support a net.IP of length 4 (e.g. ip := net.IP([]byte{1, 2, 3, 4}) will work) all the ones they generate are 16 bytes. Since you make a whole bunch, if you care about a few bytes of space, or if you care what happens after 255.255.255.255, you can avoid this for IPv4 like so:

func dupIP(ip net.IP) net.IP {
	// To save space, try and only use 4 bytes
	if x := ip.To4(); x != nil {
		ip = x
	}
	dup := make(net.IP, len(ip))
	copy(dup, ip)
	return dup
}

You may want to do something different for IPv6 addresses, I don't think it makes sense to "increment" an IPv6 the way you do, I could be wrong though.

Modified version of your original:
https://play.golang.org/p/GP9vASvUgh

huangapple
  • 本文由 发表于 2015年4月19日 23:53:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/29732128.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定