AlexBrand
AlexBrand

Reputation: 12429

Stringer implementation without using Sprintf

I am working through the golang tour and I am stuck in one of the exercises. I am not sure why the following does not work for a String() function:

type IPAddr [4]byte

func (addr IPAddr) String() string {
    return string(addr[0]) + "." + string(addr[1]) + "." + string(addr[2]) + "." + string(addr[3])
}

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

Output:

loopback: ...
googleDNS: ...

Granted that using fmt.Sprintf() would be a nicer solution, but I'm not sure I understand why that function doesn't work.

Upvotes: 2

Views: 437

Answers (2)

dolmen
dolmen

Reputation: 8706

A more efficient implementation with less temporary memory allocations:

func (addr IPAddr) String() string {
    buf := make([]byte, 0, 3+1+3+1+3+1+3)
    return string(
        strconv.AppendInt(
            append(
                strconv.AppendInt(
                    append(
                        strconv.AppendInt(
                            append(
                                strconv.AppendInt(buf,
                                    int64(addr[0]), 10), '.'),
                            int64(addr[1]), 10), '.'),
                    int64(addr[2]), 10), '.'),
            int64(addr[3]), 10))
}

Upvotes: 0

Zikes
Zikes

Reputation: 5886

What's happening there is that you're passing the byte e.g. 127 directly into string and expecting it to represent that byte as the integer 127 before converting it into a string. Instead what it's doing is interpreting it as a character with the byte value 127.

Instead you should convert that byte value into an integer, then use the strconv library to format it as a string.

package main

import (
    "fmt"
    "strconv"
)

type IPAddr [4]byte

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

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

Output:

loopback: 127.0.0.1
googleDNS: 8.8.8.8

Upvotes: 7

Related Questions