模块 6 · 第 4 课(共 5)课程中的29/50~10 min
模块课程(4/5)
斯金格接口
fmt.Stringer 可能是所有接口中最常用的标准接口
Go 的标准库。是实力的完美展现
小接口。
定义
Go
type Stringer interface {
String() string
}单一签名。任何定义 String() string 的类型都满足
它。并且 fmt 识别此接口:当您将值传递给
fmt.Print*,如果它实现 Stringer,则为 String() 的结果
使用而不是默认表示。
例子
Go
type Point struct{ X, Y int }
func (p Point) String() string {
return fmt.Sprintf("(%d,%d)", p.X, p.Y)
}
fmt.Println(Point{1, 2}) // (1,2)
fmt.Printf("%v %s\n", Point{3, 4}, Point{5, 6})
// (3,4) (5,6)在 %v、%s、Println 中以自定义格式打印相同的值,
Sprint、log 等。所有这些都只需定义一种方法即可。
当它有意义时
- 模拟域的类型(id、代码、坐标、枚举)。
- 人类可读表示的错误(请参阅下一课的
error)。 - 您经常记录并且需要固定格式的类型。
不适用于所有情况:如果类型很简单且默认表示形式 很好,不要添加噪音。
枚举类型:带有 iota 的常见模式
Go
type Status int
const (
OK Status = iota
WARN
ERR
)
func (s Status) String() string {
switch s {
case OK: return "OK"
case WARN: return "WARN"
case ERR: return "ERR"
default: return "UNKNOWN"
}
}
fmt.Println(OK, WARN, ERR) // OK WARN ERR如果没有 String(),fmt.Println(OK) 将打印 0。使用 String(),
它打印符号名称。 stringer
工具自动生成此模式。
注意无限递归
Go
type T int
func (t T) String() string {
return fmt.Sprintf("%d", int(t)) // OK: cast to int breaks the recursion
}指针接收器上的纵梁
如果 String() 有指针接收器,则只有 *T 满足 Stringer。
通过 fmt.Println(t) (一个值),Go 查看 T 的方法集,
找不到它,并使用默认格式。为了避免这种情况,值
receive 通常用于 String() (它是一个“视图”;它不是
修改任何内容)。
尝试一下
锻炼#go.m6.l4.e1
尝试:0加载中...
在 Point 上实现 String(),使其返回 (X,Y)。
正在加载编辑器...
显示提示
使用“fmt.Sprintf”格式化字段。
3 次尝试后可用的解决方案
锻炼#go.m6.l4.e2
尝试:0加载中...
在类型 Status (int) 上实现 String():0 → 'OK',1 → 'WARN',否则 → 'ERR'。
正在加载编辑器...
显示提示
打开接收器的值;请记住提供默认值。
3 次尝试后可用的解决方案
Quiz#go.m6.l4.e3
准备好该方法必须满足哪个签名才能满足 fmt.Stringer?
Go
func (x T) ??? {}回顾
fmt.Stringer = interface { String() string }。- 实现它会改变
fmt.Print*表示类型的方式。 - 枚举 (
iota)、域类型、代码/标识符的惯用语。 - 切勿在
String()内的t上调用fmt.Sprintf("%s", t)(递归)。 - 约定:
String()的值接收器(无突变,避免“方法集意外”)。