接口和类型
接口定义
接口定义了一组方法的集合,任何实现了这些方法的类型都实现了该接口。
基本语法
go
type InterfaceName interface {
Method1(param type) returnType
Method2(param type) returnType
}示例
go
// 定义接口
type Shape interface {
Area() float64
Perimeter() float64
}
// 实现接口
type Rectangle struct {
Width float64
Height float64
}
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
func (r Rectangle) Perimeter() float64 {
return 2 * (r.Width + r.Height)
}
type Circle struct {
Radius float64
}
func (c Circle) Area() float64 {
return 3.14159 * c.Radius * c.Radius
}
func (c Circle) Perimeter() float64 {
return 2 * 3.14159 * c.Radius
}
// 使用接口
func printArea(s Shape) {
fmt.Printf("面积: %.2f\n", s.Area())
}
func main() {
rect := Rectangle{Width: 10, Height: 5}
circle := Circle{Radius: 5}
printArea(rect) // 面积: 50.00
printArea(circle) // 面积: 78.54
}接口实现
在 Go 中,接口的实现是隐式的。只要类型实现了接口中的所有方法,就自动实现了该接口。
go
type Writer interface {
Write([]byte) (int, error)
}
// 任何实现了 Write 方法的类型都实现了 Writer 接口
type FileWriter struct {
filename string
}
func (f FileWriter) Write(data []byte) (int, error) {
// 实现写入逻辑
return len(data), nil
}接口组合
接口可以组合,形成更大的接口:
go
type Reader interface {
Read([]byte) (int, error)
}
type Writer interface {
Write([]byte) (int, error)
}
// 组合接口
type ReadWriter interface {
Reader
Writer
}
// 或者直接定义
type ReadWriter interface {
Read([]byte) (int, error)
Write([]byte) (int, error)
}类型断言
类型断言用于检查接口值的具体类型。
基本用法
go
var i interface{} = "hello"
// 方式 1: 两个返回值
s, ok := i.(string)
if ok {
fmt.Println("是字符串:", s)
}
// 方式 2: 一个返回值(如果失败会 panic)
s := i.(string)Type Switch
go
func doSomething(i interface{}) {
switch v := i.(type) {
case int:
fmt.Printf("整数: %d\n", v)
case string:
fmt.Printf("字符串: %s\n", v)
case bool:
fmt.Printf("布尔值: %t\n", v)
default:
fmt.Printf("未知类型: %T\n", v)
}
}空接口
空接口 interface{} 可以表示任何类型:
go
// 空接口
var i interface{}
i = 42
i = "hello"
i = true
// 使用空接口作为参数
func printValue(v interface{}) {
fmt.Println(v)
}类型别名
Go 1.18+ 引入了 any 作为 interface{} 的别名:
go
func printValue(v any) {
fmt.Println(v)
}接口的零值
接口的零值是 nil:
go
var w Writer // w 是 nil接口值
接口值包含两部分:
- 具体类型(动态类型)
- 该类型的值(动态值)
go
var w Writer
w = FileWriter{filename: "test.txt"}
// w 的类型是 FileWriter,值是 FileWriter{filename: "test.txt"}常见接口示例
io.Reader 和 io.Writer
go
import "io"
func copyData(r io.Reader, w io.Writer) error {
data := make([]byte, 1024)
for {
n, err := r.Read(data)
if n > 0 {
w.Write(data[:n])
}
if err == io.EOF {
break
}
if err != nil {
return err
}
}
return nil
}fmt.Stringer
go
type Person struct {
Name string
Age int
}
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) // 自动调用 String() 方法
}error 接口
go
type error interface {
Error() string
}
// 自定义错误
type MyError struct {
Message string
}
func (e *MyError) Error() string {
return e.Message
}
func doSomething() error {
return &MyError{Message: "发生了错误"}
}接口最佳实践
- 保持接口小巧:接口应该只包含必要的方法
- 接受接口,返回具体类型:函数参数使用接口,返回值使用具体类型
- 使用组合而非继承:通过接口组合实现复杂功能
go
// 好的设计:小巧的接口
type Reader interface {
Read([]byte) (int, error)
}
type Writer interface {
Write([]byte) (int, error)
}
// 通过组合实现复杂功能
type ReadWriter interface {
Reader
Writer
}完整示例
go
package main
import "fmt"
// 定义接口
type Animal interface {
Speak() string
Move() string
}
// 实现接口
type Dog struct {
Name string
}
func (d Dog) Speak() string {
return fmt.Sprintf("%s 说: 汪汪", d.Name)
}
func (d Dog) Move() string {
return fmt.Sprintf("%s 在跑", d.Name)
}
type Cat struct {
Name string
}
func (c Cat) Speak() string {
return fmt.Sprintf("%s 说: 喵喵", c.Name)
}
func (c Cat) Move() string {
return fmt.Sprintf("%s 在走", c.Name)
}
// 使用接口
func describeAnimal(a Animal) {
fmt.Println(a.Speak())
fmt.Println(a.Move())
}
func main() {
dog := Dog{Name: "旺财"}
cat := Cat{Name: "咪咪"}
describeAnimal(dog)
describeAnimal(cat)
// 类型断言
var a Animal = Dog{Name: "小黑"}
if dog, ok := a.(Dog); ok {
fmt.Println("这是一只狗:", dog.Name)
}
}下一步
现在你已经掌握了 Go 语言的基础知识,接下来我们将学习:
