不使用Sprintf的Stringer实现

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, 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.

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, a)
    }
}

Output:

loopback: 127.0.0.1
googleDNS: 8.8.8.8

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))
}