HiveBrain v1.2.0
Get Started
← Back to all entries
patterngoMinor

Go string formatting

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
formattingstringstackoverflow

Problem

I'm very new to Go, and am trying to get some experience by re-writing some of my Python code in Go. Below is a function that takes an IP address (ipv4) in integer form and returns the string version. From 572779703 to 34.35.236.183 for example.

func int2ip(num int) (string) {
    result   := [4]int{}
    for i, n := range []uint{24, 16, 8, 0} {
        result[i] = (num >> n) & 255
    }
    return fmt.Sprintf("%d.%d.%d.%d", result[0], result[1], result[2], result[3])
}


I'm not only curious if there is a more straightforward or concise way to do this with Go, but am very curious if there is a way to use the []result array in Sprintf() without having to type out every index.

Something similar to:

fmt.Sprintf("%d.%d.%d.%d", result)

Solution

The proper way of doing this is to use the tools the language already gave you.

IPv4 usually are stored as big endian numbers, and Go already have an IP type:

func int2ip(num int) net.IP {
    var b [4]byte
    binary.BigEndian.PutUint32(b[:], uint32(num))
    return net.IPv4(b[0], b[1], b[2], b[3])
}

//or if you don't care about returning net.IP
func int2ipstr(num int) string {
    var b [4]byte
    binary.BigEndian.PutUint32(b[:], uint32(num))
    return fmt.Sprintf("%d.%d.%d.%d", b[0], b[1], b[2], b[3])
}


playground

//edit adding more details following @Schism's advice

Using Sprintf is usually fine and they worked on optimizing it fairly well, if you want to squeeze every drop of performance out of it, you could use a more "buffered" alternative like :

func int2ipb(num int) string {
    b, buf := [4]byte{}, make([]byte, 0, 15) //15 = max number of bytes in an ip
    binary.BigEndian.PutUint32(b[:], uint32(num))
    for _, n := range b {
        buf = append(buf, '.')
        buf = append(buf, strconv.Itoa(int(n))[:]...)
    }
    return string(buf[1:])
}

Code Snippets

func int2ip(num int) net.IP {
    var b [4]byte
    binary.BigEndian.PutUint32(b[:], uint32(num))
    return net.IPv4(b[0], b[1], b[2], b[3])
}

//or if you don't care about returning net.IP
func int2ipstr(num int) string {
    var b [4]byte
    binary.BigEndian.PutUint32(b[:], uint32(num))
    return fmt.Sprintf("%d.%d.%d.%d", b[0], b[1], b[2], b[3])
}
func int2ipb(num int) string {
    b, buf := [4]byte{}, make([]byte, 0, 15) //15 = max number of bytes in an ip
    binary.BigEndian.PutUint32(b[:], uint32(num))
    for _, n := range b {
        buf = append(buf, '.')
        buf = append(buf, strconv.Itoa(int(n))[:]...)
    }
    return string(buf[1:])
}

Context

StackExchange Code Review Q#60399, answer score: 2

Revisions (0)

No revisions yet.