Golang interface 关键字
最后修改于 2025 年 5 月 7 日
本教程解释了如何在 Go 中使用 interface 关键字。我们将通过多态的实际示例涵盖接口基础知识。
interface 类型定义了一组方法签名。任何实现了这些方法的类型都隐式地满足该接口。
在 Go 中,接口实现了多态和灵活的代码设计。如果不同类型实现了相同的接口,则可以统一对待它们。
基本接口定义
一个简单的接口定义了没有实现的方法签名。此示例显示了一个基本接口及其实现。
package main
import "fmt"
type Speaker interface {
Speak() string
}
type Dog struct{}
func (d Dog) Speak() string {
return "Woof!"
}
type Cat struct{}
func (c Cat) Speak() string {
return "Meow!"
}
func main() {
animals := []Speaker{Dog{}, Cat{}}
for _, animal := range animals {
fmt.Println(animal.Speak())
}
}
Speaker 接口需要一个 Speak 方法。Dog 和 Cat 都实现了它,从而可以进行多态使用。
空接口
空接口 interface{} 没有方法。所有类型都实现了它,这使得它对于泛型函数很有用。
package main
import "fmt"
func describe(i interface{}) {
fmt.Printf("Type: %T, Value: %v\n", i, i)
}
func main() {
describe(42)
describe("hello")
describe(3.14)
describe([]int{1, 2, 3})
}
describe 函数通过空接口接受任何类型。它打印传递给它的任何内容的类型和值。
接口组合
接口可以嵌入其他接口以创建更复杂的契约。此示例组合了多个接口。
package main
import "fmt"
type Walker interface {
Walk()
}
type Runner interface {
Run()
}
type Athlete interface {
Walker
Runner
}
type Human struct{}
func (h Human) Walk() {
fmt.Println("Human walking")
}
func (h Human) Run() {
fmt.Println("Human running")
}
func main() {
var athlete Athlete = Human{}
athlete.Walk()
athlete.Run()
}
Athlete 结合了 Walker 和 Runner。Human 实现了这两种方法,满足了复合接口。
类型断言
类型断言检查接口值是否保存了特定类型。此示例演示了安全的类型检查。
package main
import "fmt"
func checkType(i interface{}) {
if s, ok := i.(string); ok {
fmt.Printf("It's a string: %s\n", s)
} else if n, ok := i.(int); ok {
fmt.Printf("It's an int: %d\n", n)
} else {
fmt.Printf("Unknown type: %T\n", i)
}
}
func main() {
checkType("hello")
checkType(42)
checkType(3.14)
}
checkType 函数使用类型断言来确定接口值的底层类型,并妥善处理每种情况。
类型开关
类型开关简化了具有多个情况的类型断言。此示例显示了一种更清晰地处理不同类型的方法。
package main
import "fmt"
func process(i interface{}) {
switch v := i.(type) {
case int:
fmt.Printf("Integer: %d\n", v)
case string:
fmt.Printf("String: %s\n", v)
case bool:
fmt.Printf("Boolean: %v\n", v)
default:
fmt.Printf("Unknown type: %T\n", v)
}
}
func main() {
process(42)
process("gopher")
process(true)
process(3.14)
}
类型开关语法 i.(type) 以清晰、可读的方式检查多种可能的类型。每种情况处理一种不同的类型。
实际示例:数据库抽象
接口在创建抽象方面非常强大。此示例展示了一个简单的数据库接口,具有多种实现。
package main
import "fmt"
type Database interface {
Connect() string
Query(q string) string
}
type MySQL struct{}
func (m MySQL) Connect() string {
return "MySQL connected"
}
func (m MySQL) Query(q string) string {
return fmt.Sprintf("MySQL query: %s", q)
}
type PostgreSQL struct{}
func (p PostgreSQL) Connect() string {
return "PostgreSQL connected"
}
func (p PostgreSQL) Query(q string) string {
return fmt.Sprintf("PostgreSQL query: %s", q)
}
func main() {
databases := []Database{MySQL{}, PostgreSQL{}}
for _, db := range databases {
fmt.Println(db.Connect())
fmt.Println(db.Query("SELECT * FROM users"))
}
}
Database 接口定义了通用操作。两种数据库类型都实现了它,允许尽管实现不同但使用方式统一。
接口实现验证
Go 可以在编译时验证类型是否满足接口。此示例显示了显式的接口实现检查。
package main
import "fmt"
type Writer interface {
Write([]byte) (int, error)
}
type ConsoleWriter struct{}
func (cw ConsoleWriter) Write(data []byte) (int, error) {
n, err := fmt.Println(string(data))
return n, err
}
func main() {
var w Writer = ConsoleWriter{}
w.Write([]byte("Hello, interfaces!"))
// Compile-time check
var _ Writer = (*ConsoleWriter)(nil)
}
行 var _ Writer = (*ConsoleWriter)(nil) 在编译时验证 ConsoleWriter 是否满足 Writer。这是 Go 中常见的惯用法。
来源
本教程通过多态、类型断言和接口组合的实际示例,涵盖了 Go 中的 interface 关键字。