• 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 接口。

    接口类型断言

    再来看一个很复杂的例子,我们将上面的代码稍作修改,将 WechatLogin 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
    }
  • 相关阅读:
    yolo数据增强
    黑盒测试的优缺点(文档+视频讲解)
    专注于绘画,不受限制!尝试Growly Draw for Mac的快速绘画应用
    极速系列04—python批量获取word中的表格
    NVM 快速安装教程,只此一家
    MVC、MVP、MVVM三种架构对比
    【数据结构】广义表与二叉树之间的转换
    Kafka、ActiveMQ、RabbitMQ、RocketMQ 的区别
    浅谈C/C++指针和引用在Linux和Windows不同环境下的编码风格
    【Linux】缓冲区/回车换行
  • 原文地址:https://www.cnblogs.com/oldme/p/18015328