首页 / Go 语言入门教程 / 常用标准接口

Go 语言入门教程

常用标准接口

本教程共 80 篇 · 第 46 篇 · 更新于 2026-07-27 · 约 8 分钟阅读

GoGo 入门教程接口StringererrorReaderWritersort.Interface

46. 常用标准接口

本节目标:认识 Go 标准库里最常用的几个接口,学会实现它们,让你的类型和标准库无缝配合。

fmt.Stringer:自定义打印格式

fmt.Stringer 接口只有一个方法,控制类型被 fmt 包打印时的输出:

type Stringer interface {
    String() string
}

实现了 String() 方法的类型,在 fmt.Printlnfmt.Printf 等函数里会自动调用它:

package main

import "fmt"

type Person struct {
    Name string
    Age  int
}

// 实现 fmt.Stringer
func (p Person) String() string {
    return fmt.Sprintf("%s(%d岁)", p.Name, p.Age)
}

func main() {
    p := Person{Name: "Alice", Age: 30}
    fmt.Println(p)         // Alice(30岁)  自动调用 String()
    fmt.Printf("%v\n", p)  // Alice(30岁)
    fmt.Printf("%+v\n", p) // Alice(30岁)  %+v 也走 String()
    fmt.Printf("%#v\n", p) // main.Person{Name:"Alice", Age:30}  %#v 不走 String()
}
Tip

实现了 Stringer 后,fmt.Println(p)fmt.Printf("%v", p)%+v 都会调用 String()。只有 %#v 不会,它会用 Go 语法显示结构体的原始结构。

Warning

String() 方法里不要递归调用自己。比如 fmt.Sprintf("%v", p)p 就是当前类型,会再次触发 String(),导致无限递归。

error:错误接口

error 是 Go 里最重要的接口之一:

type error interface {
    Error() string
}

任何实现了 Error() string 方法的类型都可以作为 error 使用:

package main

import "fmt"

// 自定义错误类型
type ValidationError struct {
    Field   string
    Message string
}

func (e *ValidationError) Error() string {
    return fmt.Sprintf("验证失败 [%s]: %s", e.Field, e.Message)
}

func validateAge(age int) error {
    if age < 0 {
        return &ValidationError{
            Field:   "age",
            Message: "年龄不能为负数",
        }
    }
    return nil
}

func main() {
    err := validateAge(-5)
    if err != nil {
        fmt.Println(err) // 验证失败 [age]: 年龄不能为负数
    }
}

错误处理是 Go 的核心设计,后面有几章专门讲这个。

io.Reader 和 io.Writer:读写接口

io.Readerio.Writer 是 Go 里最通用的 IO 接口:

type Reader interface {
    Read(p []byte) (n int, err error)
}

type Writer interface {
    Write(p []byte) (n int, err error)
}

几乎所有涉及数据读写的类型都实现了这两个接口:文件、网络连接、缓冲区、压缩流等等。因为接口统一,你可以用同一套代码处理不同的 IO 源。

来看一个实现 io.Writer 的例子──一个把写入的数据变成大写的 Writer:

package main

import (
    "fmt"
    "io"
    "strings"
)

type UpperWriter struct {
    W io.Writer
}

func (uw *UpperWriter) Write(p []byte) (n int, err error) {
    upper := strings.ToUpper(string(p))
    return uw.W.Write([]byte(upper))
}

func main() {
    // 把 UpperWriter 包在 strings.Builder 外面
    w := &UpperWriter{W: &strings.Builder{}}
    w.Write([]byte("hello world"))

    builder := w.W.(*strings.Builder)
    fmt.Println(builder.String()) // HELLO WORLD
}
Note

io.ReaderRead 方法约定:读取数据填入 p,返回读取的字节数。读到末尾返回 io.EOF。这个约定让所有 Reader 可以互换使用。

io.ReadWriter:组合接口

标准库用接口组合定义了 io.ReadWriter

type ReadWriter interface {
    Reader
    Writer
}

文件(*os.File)就实现了 ReadWriter,既能读又能写。

sort.Interface:排序接口

要给自定义类型排序,可以实现 sort.Interface 的三个方法:

type Interface interface {
    Len() int
    Less(i, j int) bool
    Swap(i, j int)
}

不过从 Go 1.21 开始,有了 slices.SortFunc,你不需要再实现这三个方法了。但了解 sort.Interface 还是有必要的,因为很多老代码和第三方库在用。

来看一个实现 sort.Interface 的例子:

package main

import (
    "fmt"
    "sort"
)

type ByAge []Person

type Person struct {
    Name string
    Age  int
}

func (a ByAge) Len() int           { return len(a) }
func (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age }
func (a ByAge) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }

func main() {
    people := []Person{
        {"Alice", 30},
        {"Bob", 25},
        {"Charlie", 35},
    }

    sort.Sort(ByAge(people))
    fmt.Println(people)
    // [{Bob 25} {Alice 30} {Charlie 35}]
}
Tip

Go 1.21+ 推荐用 slices.SortFunc 替代 sort.Sort,不需要定义新类型:

slices.SortFunc(people, func(a, b Person) int {
    return cmp.Compare(a.Age, b.Age)
})

其他常用接口速览

接口方法用途
fmt.StringerfmtString()自定义打印格式
errorbuiltinError()错误表示
io.ReaderioRead()读取数据
io.WriterioWrite()写入数据
io.CloserioClose()关闭资源
sort.InterfacesortLen/Less/Swap排序
json.Marshalerencoding/jsonMarshalJSON()自定义JSON序列化
json.Unmarshalerencoding/jsonUnmarshalJSON()自定义JSON反序列化
http.Handlernet/httpServeHTTP()HTTP请求处理

小结

标准库接口是 Go 编程的基础设施:

  • fmt.Stringer:控制打印输出
  • error:表示错误
  • io.Reader/Writer:统一读写抽象
  • sort.Interface:排序(Go 1.21+ 推荐用 slices.SortFunc)

实现这些接口能让你的类型和标准库无缝配合。下一部分进入泛型,Go 类型系统的现代化升级。