接口是隐式实现的,不需要显式声明
例如,我们定义了一个接口 MyInterface ,它包含两个方法 Method1 和 Method2 。如果我们定义了一个结构体 MyStruct ,并为它实现了这两个方法,那么 MyStruct 就隐式地实现了 MyInterface ,不需要在代码中声明。
type MyInterface interface {
Method1() string
Method2(int) int
}
type MyStruct struct {
name string
age int
}
func (m *MyStruct) Method1() string {
return m.name
}
func (m *MyStruct) Method2(n int) int {
return m.age + n
}
func main() {
var mi MyInterface // 声明一个接口变量
mi = &MyStruct{"Alice", 20} // 赋值为一个结构体指针,隐式实现接口
fmt.Println(mi.Method1()) // 调用接口方法
fmt.Println(mi.Method2(10))
}
接口可以嵌套组合,形成更复杂的接口
例如,我们定义了两个接口 Reader 和 Writer ,它们分别包含 Read 和 Write 方法。我们可以通过嵌套这两个接口来定义一个新的接口 ReadWriter ,它包含了 Read 和 Write 方法。
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
type ReadWriter interface {
Reader // 嵌套 Reader 接口
Writer // 嵌套 Writer 接口
}
接口可以赋值给任何类型的变量,也可以作为函数参数或返回值
例如,我们定义了一个函数 PrintStringer ,它接受一个 fmt.Stringer 类型的参数,并打印其 String 方法的返回值。fmt.Stringer 是 Go 语言中内置的一个接口,它只包含一个 String 方法。任何类型只要实现了 String 方法,就可以作为 PrintStringer 的参数。
func PrintStringer(s fmt.Stringer) {
fmt.Println(s.String())
}
type Person struct {
name string
age int
}
// 实现 String 方法,满足 fmt.Stringer 接口要求
func (p Person) String() string {
return fmt.Sprintf("name: %s, age: %d", p.name, p.age)
}
func main() {
p := Person{"Bob", 25}
PrintStringer(p) // 将 Person 类型作为参数传递给 PrintStringer 函数
}
接口可以使用类型断言或反射来获取具体类型或值
例如,我们定义了一个空接口 interface{} 类型的变量 i ,并赋值为整数 42 。空接口可以表示任意类型的值。如果我们想要获取 i 的具体类型和值,我们可以使用类型断言或反射来实现。
import (
"fmt"
"reflect"
)
func main() {
var i interface{} = 42 // 定义并赋值空接口变量
// 使用类型断言获取具体类型和值
if v, ok := i.(int); ok {
fmt.Printf("i is an int with value %d\n", v)
} else {
fmt.Println("i is not an int")
}
// 使用反射获取具体类型和值
t := reflect.TypeOf(i) // 获取 i 的反射类型对象
v := reflect.ValueOf(i) // 获取 i 的反射值对象
fmt.Printf("i is a %s with value %v\n", t.Name(), v.Interface())
}