Go 中烧脑的接口及空接口
作者:灯火消逝的码头
基本定义
Go 官方对于接口的定义是一句话:An interface type is defined as a set of method signatures. 翻译过来就是,一个接口定义了一组方法的集合。这和 Java 和 PHP 的接口类似,定义一组方法而不定义方法的具体实现。但是与 Java 和 PHP 迥然不同的地方在于 Go 不需要显式的声明 implements
关键词来继承接口,一个类型只要实现了接口中的所有方法,就视作继承了该接口,是隐式实现的。来看一个基本的使用示例:
// 定义一个平台接口,包含一个支付方法 type Platform interface { Pay(amount int) error } // 微信平台 type Wechat struct{} func (w *Wechat) Pay(amount int) error { fmt.Printf("wechat amount: %d\n", amount) return nil } // 支付宝平台 // 任意值都可以实现接口,并非一定需要struct type Alipay int func (a Alipay) Pay(amount int) error { fmt.Printf("alipay amount: %d, a: %d\n", amount, a) return nil } func ExamplePlatform() { var ( p Platform w = Wechat{} a Alipay = 1 ) p = &w p.Pay(2) p = &a p.Pay(3) // 这种写法会报错 // p = w p = a p.Pay(4) // Output: // wechat amount: 2 // alipay amount: 3, a: 1 // alipay amount: 4, a: 1 }
在这个示例中,我们定义了一个 Platform
接口和两个结构体,分别使用了值接收器和指针接收器来实现了 Platform
接口。p = w
这行代码会报错,究其原因是,对于使用指针接收器实现的接口的 Wechat
,只有它的指针会实现接口,值不会实现;而对于值实现接口的 Alipay
,指针和值都会实现接口。所以 p = a
可以正常运行。
接口嵌套
接口可以嵌套另一个接口:
// 定义一个平台接口,包含一个支付方法 type Platform interface { Pay(amount int) error User } type User interface { Login() Logout() } // 微信平台 type Wechat struct{} func (w *Wechat) Pay(amount int) error { fmt.Printf("wechat amount: %d\n", amount) return nil } func (w *Wechat) Login() {} func (w *Wechat) Logout() {}
此时,Wechat
即实现了 Platform
接口,也实现了 User
接口。
接口类型断言
再来看一个很复杂的例子,我们将上面的代码稍作修改,将 Wechat
的 Login
和Logout
提到另一个结构中,然后使用类型断言判断 Wechat
是否实现了 User
接口:
// 定义一个平台接口,包含一个支付方法 type Platform interface { Pay(amount int) error User } type User interface { Login() Logout() } type UserS struct { } func (u *UserS) Login() {} func (u *UserS) Logout() {} // 微信平台 type Wechat struct { UserS } func (w *Wechat) Pay(amount int) error { fmt.Printf("wechat amount: %d\n", amount) return nil } func ExamplePlatform() { var ( p Platform w = Wechat{} ) p = &w p.Pay(2) // 类型断言 _, ok := p.(User) fmt.Println(ok) // Output: // wechat amount: 2 // true }
空接口
Go 1.18 新增了一个新的变量类型:any
,其定义如下:
type any = interface{}
其实 any 就是一个空接口,对于空接口而言,它没有任何方法,所以对于任意类型的值都相当于实现了空接口,这个概念和另一个编程概念十分相似,它就是大名鼎鼎的泛型。在 Go 语言中,fmt.Println
函数的接收值正是一个 any
:
func Println(a ...any) (n int, err error) { return Fprintln(os.Stdout, a...) }
使用空接口搭配类型断言,我们可以设计出一个简单的类型转换函数,它将任意类型的值转为 int:
func ToInt(i any) int { switch v := i.(type) { case int: return v case float64: return int(v) case bool: if v { return 1 } return 0 case string: vint, _ := strconv.Atoi(v) return vint } return 0 }
到此这篇关于Go 中烧脑的接口的文章就介绍到这了,更多相关Go 接口内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!