Stringer 接口
自定义类型的打印方式
Stringer 接口 是 CoddyKit 上的免费 Go Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Go Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Go Academy 课程共包含 4 节课。
结构体的默认打印方式
默认情况下,使用 %v 打印结构体时会显示其原始字段。这对于调试很合适,但不一定便于读者理解。
package main
import "fmt"
type Color struct{ R, G, B int }
func main() {
c := Color{255, 0, 0}
fmt.Println(c)
}Stringer 接口
fmt.Stringer 接口包含一个方法:
String() string
任何定义了该方法的类型都可以控制自身被打印时的显示方式。
package main
import "fmt"
type Greeting struct{ Name string }
func (g Greeting) String() string {
return "Hello, " + g.Name
}
func main() {
fmt.Println(Greeting{"Ada"})
}会自动使用
当类型拥有 String() 方法时,Println、使用 %v 或 %s 的 Printf 以及其他相关函数都会自动调用它。
package main
import "fmt"
type Greeting struct{ Name string }
func (g Greeting) String() string {
return "Hi " + g.Name
}
func main() {
g := Greeting{"Bob"}
fmt.Printf("%s and %v\n", g, g)
}在 String() 中进行格式化
使用 fmt.Sprintf 构建结果,以生成简洁且自定义的表示形式。
package main
import "fmt"
type Color struct{ R, G, B int }
func (c Color) String() string {
return fmt.Sprintf("rgb(%d, %d, %d)", c.R, c.G, c.B)
}
func main() {
fmt.Println(Color{255, 128, 0})
}命名类型上的 Stringer
Stringer 不仅适用于结构体。任何命名类型都可以实现它,即使该类型基于 int。这就是经典的枚举模式。
package main
import "fmt"
type Day int
func (d Day) String() string {
names := []string{"Mon", "Tue", "Wed"}
return names[d]
}
func main() {
fmt.Println(Day(1))
}打印效果良好的枚举
将 iota 与 Stringer 结合使用,就可以让常量打印为易读的名称,而不是数字。
package main
import "fmt"
type State int
const (
Idle State = iota
Running
Done
)
func (s State) String() string {
return []string{"Idle", "Running", "Done"}[s]
}
func main() {
fmt.Println(Running)
}值接收者与指针接收者
如果 String() 使用值接收者,值和指针都能以良好的格式打印。使用指针接收者时,只有指针会触发该方法。
package main
import "fmt"
type Tag struct{ Name string }
func (t Tag) String() string { return "#" + t.Name }
func main() {
t := Tag{"go"}
fmt.Println(t)
fmt.Println(&t)
}避免无限递归
不要在类型自己的 String() 方法中对同一类型调用 fmt.Sprintf("%v", t)。这会再次调用 String(),并永远重复下去。请直接格式化各个字段。
package main
import "fmt"
type Money struct{ Cents int }
func (m Money) String() string {
return fmt.Sprintf("$%.2f", float64(m.Cents)/100)
}
func main() {
fmt.Println(Money{1050})
}切片中的 Stringer
打印由 Stringer 值组成的切片时,每个元素都会使用其 String() 方法进行格式化。
package main
import "fmt"
type Tag struct{ Name string }
func (t Tag) String() string { return "#" + t.Name }
func main() {
tags := []Tag{{"go"}, {"web"}}
fmt.Println(tags)
}将其作为接口使用
您可以将任何 Stringer 存储在 fmt.Stringer 变量中,并通过该接口调用 String()。
package main
import "fmt"
type City struct{ Name string }
func (c City) String() string { return "City of " + c.Name }
func main() {
var s fmt.Stringer = City{"Oslo"}
fmt.Println(s.String())
}为什么这很重要
实现 Stringer 后,您的类型无论在哪里被打印或记录日志,都能产生整洁的输出,而不必在每个调用位置额外编写格式化代码。
package main
import "fmt"
type Temp float64
func (t Temp) String() string {
return fmt.Sprintf("%.1f°C", float64(t))
}
func main() {
fmt.Println(Temp(21.5))
}快速检查
类型必须定义哪个方法才能满足 fmt.Stringer?
回顾:Stringer 接口
您已经学会了自定义打印方式:
- 实现
String() string即可满足fmt.Stringer。 fmt会在使用%v和%s时自动调用它。- 它非常适合枚举;请避免对同一类型递归使用
%v。
package main
import "fmt"
type Level int
func (l Level) String() string {
return []string{"low", "mid", "high"}[l]
}
func main() {
fmt.Println(Level(2))
}常见问题解答
「Stringer 接口」课时是免费的吗?
是的 — 「Stringer 接口」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Go Academy 课程的其余内容,请升级到 CoddyKit PRO。 Go Academy 课程共包含 4 节课。
「Stringer 接口」这节课中我会学到什么?
自定义类型的打印方式 你通过在浏览器中直接运行的动手代码来练习 Go Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Go Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Go Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。
「Stringer 接口」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Go Academy 课中编写并运行代码吗?
能。每节 Go Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- Printf 动词
- Sprintf 与 Fprintf
- Stringer 接口
- 扫描输入