不使用Sprintf实现Stringer接口的方法

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

Stringer implementation without using Sprintf

问题

我正在通过golang教程进行学习,但在其中一个练习中遇到了问题。我不确定为什么以下的String()函数不起作用:

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

输出结果为:

loopback: ...
googleDNS: ...

虽然使用fmt.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.

答案1

得分: 7

这里发生的情况是,你直接将字节(例如127)传递给字符串,并期望它在转换为字符串之前将该字节表示为整数127。但实际上,它将其解释为具有字节值127的字符。

相反,你应该将该字节值转换为整数,然后使用strconv库将其格式化为字符串。

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

输出:

loopback: 127.0.0.1
googleDNS: 8.8.8.8
英文:

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

答案2

得分: 0

一个更高效的实现,减少了临时内存分配:

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))
}
英文:

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

huangapple
  • 本文由 发表于 2015年4月14日 04:55:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/29614943.html
匿名

发表评论

匿名网友

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

确定