接口定义
接口interface,和Java类似,是一组行为规范的集合,就是定义一组未实现的函数声明。谁使用接口就 是参照接口的方法定义实现它们。
type 接口名 interface { 方法1 (参数列表1) 返回值列表1 方法2 (参数列表2) 返回值列表2 ... }
- 接口命名习惯在接口名后面加上er后缀
- 参数列表、返回值列表参数名可以不写
- 如果要在包外使用接口,接口名应该首字母大写,方法要在包外使用,方法名首字母也要大写
- 接口中的方法应该设计合理,不要太多
Go语言中,使用组合实现对象特性的描述。对象内部使用结构体内嵌组合对象应该具有的特性,对外通 过接口暴露能使用的特性。 Go语言的接口设计是非侵入式的,接口编写者无需知道接口被哪些类型实现。而接口实现者只需知道实 现的是什么样子的接口,但无需指明实现哪一个接口。编译器知道最终编译时使用哪个类型实现哪个接 口,或者接口应该由谁来实现。 接口是约束谁应该具有什么功能,实现某接口的方法,就具有该接口的功能,简而言之,缺什么补什 么。
接口实现
如果一个结构体实现了一个接口声明的所有方法,就说结构体实现了该接口。 一个结构体可以实现多个不同接口。
package main import "fmt" type Person struct { name string age int } type Sport interface { run() jump() } func (*Person) run() { fmt.Println("Run~~~") } func (*Person) jump() { fmt.Println("Jump~~~") } func main() { p := new(Person) p.run() p.jump() }
接口嵌入
除了结构体可以嵌套,接口也可以。接口嵌套组合成了新接口。
type Reader interface { Read(p []byte) (n int, err error) } type Closer interface { Close() error } type ReadCloser interface { Reader Closer }
ReadCloser接口是Reader、Closer接口组合而成,也就是说它拥有Read、Close方法声明。
空接口
空接口,实际上是空接口类型,写作 interface {} 。为了方便使用,Go语言为它定义一个别名any类 型,即 type any = interface{} 。 空接口,没有任何方法声明,因此,任何类型都无需显式实现空接口的方法,因为任何类型都满足这个 空接口的要求。那么,任何类型的值都可以看做是空接口类型。
var a = 500 var b interface{} // 空接口类型可以适合接收任意类型的值 b = a fmt.Printf("%v, %[1]T; %v, %[2]T\n", a, b) var c = "abcd" b = c // 可以接收任意类型 fmt.Printf("%v, %[1]T; %v, %[2]T\n", c, b) b = []interface{}{100, "xyz", [3]int{1, 2, 3}} // interface{}看做一个整体。切片 元素类型任意 fmt.Printf("%v, %[1]T\n", b)
接口类型断言
接口类型断言(Type Assertions)可以将接口转换成另外一种接口,也可以将接口转换成另外的类型。 接口类型断言格式 t := i.(T)
- i代表接口变量
- T表示转换目标类型
- t代表转换后的变量 断言失败,也就是说 i 没有实现T接口的方法则panic
- t, ok := i.(T) ,则断言失败不panic,通过ok是true或false判断i是否是T类型接口
var b interface{} = 500 fmt.Println(b.(string)) // panic 转换失败 if s, ok := b.(string); ok { fmt.Println("断言成功,值是", s) } else { fmt.Println("断言失败") }
type-switch
可以使用特殊格式来对接口做多种类型的断言。
var i interface{} = 500 switch v := i.(type) { // i.(type) 只能用在switch中。 case nil: fmt.Println("nil") case string: fmt.Println("字符串", v) case int: fmt.Println("整型", v) default: fmt.Println("其他类型", v) }
输出格式接口
使用fmt.Print等函数时,对任意一个值都有一个缺省打印格式。本质上就是实现打印相关的接口。
// 普通的Print type Stringer interface { String() string } // %#v format type GoStringer interface { GoString() string }
通过实现上面的接口,就可以控制值的打印输出格式。
package main import "fmt" type Person struct { name string age int } // fmt.Stringer func (Person) String() string { return "abc" } // fmt.GoStringer func (*Person) GoString() string { return "xyz" } func (*Person) foo() string { return "foo" } func main() { p := Person{"Tom", 20} fmt.Println(p, &p) fmt.Printf("%+v, %+v\n", p, &p) fmt.Printf("%#v, %#v\n", p, &p) fmt.Printf("%s, %s\n", p.foo(), (&p).foo()) }示例
以实例的指针为例 | %v | %+v | %#v |
默认 | &{tom 20} | &{name:tom age:20} | &main.Person{name:"tom", age:20} |
实现Stringer接口 | abc | abc | |
实现GoStringer接 口 | xyz |
Stringer、GoStringer接口的方法,如果receiver如果是指针,只能对指针有作用;如果receiver是实例,实例、指针都有作用。 普通方法receiver不管是实例还是指针,实例、指针都可以调用该方法。
官方文档:https://pkg.go.dev/fmt#GoStringer
标签:语言,Person,fmt,接口,interface,go,type,string From: https://www.cnblogs.com/caibao666/p/17524882.html