'How to transform [4]byte{1,2,3,4} to "1.2.3.4" in Golang?

Here is my code which was used to transfer a byte array to string but it was failed:

package main

import (
    "bytes"
    "fmt"
)

type IPAddr [4]byte

// TODO: Add a "String() string" method to IPAddr.

func (ip IPAddr) String() string {
    s := [][]byte{ip[:]}
    //fmt.Println(s)
    sep := []byte(".")
    return string(bytes.Join(s, sep))
}

func main() {
    hosts := map[string]IPAddr{
        "loopback":  {127, 0, 0, 1},
        "googleDNS": {8, 8, 8, 8},
    }
    for name, ip := range hosts {
        fmt.Printf("%v: %v\n", name, ip)
    }
}

The program does not generate a expected output as

loopback: 127.0.0.1
googleDNS: 8.8.8.8

How to transform [4]byte{1,2,3,4} to "1.2.3.4" in Golang?

go


Solution 1:[1]

1- Use net.IP, like this working sample code:

package main

import "fmt"
import "net"

func main() {
    hosts := map[string]net.IP{
        "loopback ": {127, 0, 0, 1},
        "googleDNS": {8, 8, 8, 8},
    }
    for name, ip := range hosts {
        fmt.Println(name, ":", ip)
    }
}

output:

loopback  : 127.0.0.1
googleDNS : 8.8.8.8

2- Use this:

func (ip IPAddr) String() string {
    return strconv.Itoa(int(ip[0])) + "." +
        strconv.Itoa(int(ip[1])) + "." +
        strconv.Itoa(int(ip[2])) + "." +
        strconv.Itoa(int(ip[3]))
}

like this working sample code:

package main

import "fmt"
import "strconv"

type IPAddr [4]byte

func (ip IPAddr) String() string {
    return strconv.Itoa(int(ip[0])) + "." +
        strconv.Itoa(int(ip[1])) + "." +
        strconv.Itoa(int(ip[2])) + "." +
        strconv.Itoa(int(ip[3]))
}

func main() {
    hosts := map[string]IPAddr{
        "loopback ": {127, 0, 0, 1},
        "googleDNS": {8, 8, 8, 8},
    }
    for name, ip := range hosts {
        fmt.Println(name, ":", ip)
    }
}

output:

loopback  : 127.0.0.1
googleDNS : 8.8.8.8

3- Use strings.Trim(strings.Join(strings.Fields(fmt.Sprint(ip)), "."), "[]")
like this working sample code:

package main

import "fmt"
import "strings"

type IPAddr [4]byte

func (ip IPAddr) String() string {
    return strings.Trim(strings.Join(strings.Fields(fmt.Sprint([4]byte(ip))), "."), "[]")
}

func main() {
    hosts := map[string]IPAddr{
        "loopback ": {127, 0, 0, 1},
        "googleDNS": {8, 8, 8, 8},
    }
    for name, ip := range hosts {
        fmt.Println(name, ":", ip)
    }
}

output:

loopback  : 127.0.0.1
googleDNS : 8.8.8.8

Solution 2:[2]

You don't need to define your own type as there is already net.IP which implements fmt.Stringer.

Example:

package main

import (
    "fmt"
    "net"
)

func main() {
    ip := net.IP{127, 0, 0, 1}
    fmt.Println(ip)
}

net.IP is a byte slice, so you can also do:

b := []byte{127, 0, 0, 1}
ip := net.IP(b)
fmt.Println(ip)

Solution 3:[3]

Note that net.IP is a []byte which implements String() string so you can simply do:

net.IP{127, 0, 0, 1}.String() // => "127.0.0.1"

This strategy is much faster than fmt.Sprintf(...) or strings.Join(...):

// ip_string_test.go

var ip = net.IP{127, 0, 0, 1}

func Benchmark_net_IP_String(b *testing.B) {
  for i := 0; i < b.N; i++ {
    ip.String()
  }
}

func Benchmark_fmt_Sprintf(b *testing.B) {
  for i := 0; i < b.N; i++ {
    fmt.Sprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3])
  }
}

func Benchmark_strings_Join(b *testing.B) {
  ss := make([]string, len(ip))
  for i := 0; i < b.N; i++ {
    for i, x := range ip {
      ss[i] = strconv.FormatInt(int64(x), 10)
    }
    strings.Join(ss, ".")
  }
}

$ go test -bench=. ./ip_string_test.go

goos: darwin
goarch: amd64
Benchmark_net_IP_String-8       50000000            30.8 ns/op
Benchmark_fmt_Sprintf-8         10000000           194 ns/op
Benchmark_strings_Join-8        20000000           113 ns/op
PASS
ok      command-line-arguments  6.123s

Solution 4:[4]

type IPAddr struct {
    A byte
    B byte
    C byte
    D byte
}

func (p IPAddr) String() string {
    return fmt.Sprintf("%v.%v.%v.%v", p.A, p.B, p.C, p.D)
}

func main() {
    hosts := map[string]IPAddr{
        "loopback":  {127, 0, 0, 1},
        "googleDNS": {8, 8, 8, 8},
    }
    for name, ip := range hosts {
        fmt.Printf("%v: %v\n", name, ip)
    }
}

Solution 5:[5]

Here's how I did it.

package main

import (
    "fmt"
)

type IPAddr [4]byte


func (ip IPAddr) String() string {
    return fmt.Sprintf("%v.%v.%v.%v", int(ip[0]), int(ip[1]), int(ip[2]), int(ip[3]))
}

func main() {
    hosts := map[string]IPAddr{
        "loopback":  {127, 0, 0, 1},
        "googleDNS": {8, 8, 8, 8},
    }
    for name, ip := range hosts {
        fmt.Printf("%v: %v\n", name, ip)
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3
Solution 4 Marston Lam
Solution 5 chicks