Go 为什么可以';我做fmt.Sprintf(“d.%d.%d.%d”,a…)?

Go 为什么可以';我做fmt.Sprintf(“d.%d.%d.%d”,a…)?,go,Go,我正在学习围棋,我被围棋之旅困住了(exercise-stringer.Go:) 下面是一些代码: type IPAddr [4]byte // TODO: Add a "String() string" method to IPAddr. func (a IPAddr) String() string { return fmt.Sprintf("%d.%d.%d.%d", a...) } 所以我计算了IPAddr的内部表示是[4]字节,所以spread操作符可以工作。但我得到了:

我正在学习围棋,我被围棋之旅困住了(exercise-stringer.Go:)

下面是一些代码:

type IPAddr [4]byte  
// TODO: Add a "String() string" method to IPAddr.
func (a IPAddr) String() string {
    return fmt.Sprintf("%d.%d.%d.%d", a...)
}
所以我计算了
IPAddr
的内部表示是
[4]字节
,所以spread操作符可以工作。但我得到了:

cannot use []string literal (type []string) as type []interface {} in argument to fmt.Sprintf
怎么回事?弦片也不行,这是怎么回事

编辑:对不起,我的问题中有一个错误-错误是关于类型
IPAddr
,而不是
[]字符串
。我在玩代码,粘贴了错误的输出。总之,多亏了Go中切片的不变性

这就引出了另一个问题。为什么要这样实施呢?我想你会有一些
Iterable
接口,所以任何实现它的结构都“正常工作”

旁注:当我第一次听说Go时,有一句粗体的话“经过编译,但富有表现力”。显式接口实现就是一个很好的例子,但是像显式转换、缺少操作符重载等等给我“90年代的Java感觉”。这很可悲,因为围棋似乎是一门伟大的语言

练习:纵梁

使
IPAddr
键入implement
fmt.Stringer
将地址打印为 虚线四边形

例如,
IPAddr{1,2,3,4}
应打印为
“1.2.3.4

没有将
[]字符串
隐式转换为
[]接口{}
。再见。您需要提供显式转换。比如说,

package main

import "fmt"

type IPAddr [4]byte

// A "String() string" method for IPAddr.
func (a IPAddr) String() string {
    return fmt.Sprintf("%d.%d.%d.%d", a[0], a[1], a[2], a[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

从go语言规范:

如果f是可变的,且最终参数p的类型为…T,那么在f中,p的类型相当于类型[]T

但在Go中,切片和数组是类型不变的。如果
T
U
是不同的类型,那么
[]T
[]U
是不同的。即使
T
U
的结构子类型,它们也没有任何关系。所以
[]字符串
不是
[]接口

首先,当我“运行”时: 包干管

输入“fmt”

错误是:

prog.go:9:无法将(类型IPAddr)用作中的类型[]接口{} fmt.Sprintf的参数

而不是

无法将[]字符串文字(类型[]字符串)用作中的类型[]接口{} fmt.Sprintf的参数

所以,我认为在复制和粘贴的过程中出现了一些不同步的情况

键入IPAddr[4]字节
未定义字符串,因此问题中的错误消息具有误导性

它是一个
[4]字节
,与string完全不同(从Go语言类型的角度来看)。它也不是
[]字节

键入IPAddr[4]字节
也不能满足fmt.Sprintf可以使用的接口,例如implementstring(),因为IPAddr的String()方法无法编译

您可以尝试将
[4]字节
转换为字符串,但这种转换,
字符串(a)
是不合法的。更糟糕的是,四字节值将被视为字符代码,而不是转换为4个小整数值的字符表示形式。一些IPAddr字节值很可能是无效的UTF-8,如果程序试图打印它,这将更加奇怪

如其他答案所述,
返回fmt.Sprintf(“%d.%d.%d.%d”,a[0],a[1],a[2],a[3])

以目标格式返回IPAddr的字符串值

一旦
func(IPAddr)String()字符串有效,它就会工作
IPAddr
实现fmt.Stringer接口

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

fmt.Printf(“%v:%v\n”,n,a)


fmt.Printf(“%s:%s\n”,n,a)

因为fmt输出方法具有String()的实现


我更喜欢
%s
而不是
%v
,因为它表示程序不依赖“默认Go值表示”(即,对于该数组
[127 0 0 1]
),并且类型实现String()。

您需要为Stringer接口实现此方法

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

应使用
范围
迭代数组,因此答案如下:

func (ip IPAddr) String() string {
    out := fmt.Sprintf("%v", ip[0])
    for _, value := range ip[1:] {
        out += fmt.Sprintf(".%v", value)
    }
    return out
}

如Go FAQ部分所述,没有从类型化数组到
[]接口{}
的隐式转换:

语言规范不允许这样做,因为这两种类型 内存中没有相同的表示形式。有必要复制 将元素分别添加到目标切片

以下解决方案可行,但需要创建中间切片:

func(ip IPAddr)字符串()字符串{
tmp:=make([]接口{},len(ip))
对于i,val:=范围ip{
tmp[i]=val
}
返回fmt.Sprintf(“%d.%d.%d.%d”,tmp…)
}

添加一些关于此答案如何帮助解决当前问题的解释。虽然此代码可能会解决问题,但一个好的答案应该解释代码的作用以及它如何帮助解决问题
func (ip IPAddr) String() string {
    out := fmt.Sprintf("%v", ip[0])
    for _, value := range ip[1:] {
        out += fmt.Sprintf(".%v", value)
    }
    return out
}
func (ip IPAddr) String() string {
    var s []string;
    for _, v := range ip {
        s = append(s, fmt.Sprintf("%v", v))
    }
    return strings.Join(s, ".")
}