Go-接口类型详解(定义、实现、接口继承比较等)

简介: Go-接口类型详解(定义、实现、接口继承比较等)

简介

Go 语言中的接口是一种内置的类型,它定义了一组方法的签名,体现了程序设计的高内聚低耦合的特点,本篇文章会介绍接口及基本使用,下篇文章介绍类型断言。

结构体

定义Monkey结构体,具有climb方法。

type Monkey struct {
  Name string
}
func (m *Monkey)climb(){
  fmt.Println(m.Name,"会爬树...")
}

定义WuKong结构体,包含Monkey和Tool属性。

type WuKong struct {
  Monkey
  Tool string
}

声明/定义

定义接口模板如下:

/* 定义接口 */

type interface_name interface {

  method_name1([parameter list]) (return_type)

  method_name2 ([parameter list]) (return_type)

  ...

  method_namen([parameter list]) (return_type)

}

代码

定义Flyable接口

type Flyable interface {
  Fly()
}

实现与使用

实现

实现了接口的所有方法,就是实现了该接口,不需要显示指明是哪个接口,即隐式实现

func (w *WuKong) Fly() {
  fmt.Println("筋斗云,来...")
}

鸭子类型

鸭子类型duck typing)是动态类型的一种风格,例如,Python语言中比较常见。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由"当前方法和属性集合"决定。

而在Go中,就是由当前结构体的方法集合决定当前结构体是否实现了某个接口。WuKong可以飞,而Monkey不可以飞,WuKong在继承Monkey的基础上,扩展了自己的功能。

多接口实现

再定义一个接口

1. type Swimmable interface {
2.  Swim()
3. }

实现

func (w *WuKong) Swim()  {
  fmt.Println("老龙王,俺老孙的金箍棒呢?")
}

WuKong结构体就实现了上面的两个接口。

接口继承

再定义一个接口Skills,继承前面的两个接口,并添加新的方法Change

type Skills interface {
  Flyable
  Swimmable
  Change()
}

实现

func (w *WuKong) Change()  {
  fmt.Println("看我72变...")
}

至此, WuKong结构体实现了四个接口,为什么是四个呢?因为还有下面这一个

空接口

type Null interface {
}

如你所见,什么方法也没有,即每个结构体都实现了空接口,都可以赋值给空接口,这在排序,后面类型断言等部分都很有用。

结构体切片排序

func Sort(data Interface)

Sort,本地排序data,无返回。它调用1次data.Len确定长度,调用O(n*log(n))次data.Less和data.Swap,底层使用的是快排,感兴趣的朋友可以看看快排源代码。本函数不能保证排序的稳定性(即不保证相等元素的相对次序不变)。

// Sort sorts data.
// It makes one call to data.Len to determine n and O(n*log(n)) calls to
// data.Less and data.Swap. The sort is not guaranteed to be stable.
func Sort(data Interface) {
  n := data.Len()
  quickSort(data, 0, n, maxDepth(n))
}

Interface接口

type Interface interface {
  // Len is the number of elements in the collection.
  Len() int
        // Less reports whether the element with index i must sort before the element with index j.
  // See Float64Slice.Less for a correct implementation for floating-point values.
  Less(i, j int) bool
  // Swap swaps the elements with indexes i and j.
  Swap(i, j int)
}

既然这是一个接口,只要我们实现了Len、Less、Swap方法即可传参,进行排序。

我们就用Monkey结构体的切片实现一下这个接口。

type MonkeySlice []Monkey
//--------实现Len--------
func (m MonkeySlice) Len() int{
  return len(m)
}
//---------实现Less---------
func (m MonkeySlice) Less(i,j int) bool {
  return m[i].Name < m[j].Name
}
//----------实现Swap---------
func (m MonkeySlice) Swap(i,j int){
  m[i],m[j] = m[j],m[i]
}

使用

  monkeys := MonkeySlice{{"峨眉猴"},{"齐天大圣"},{"金丝猴"},{"六耳猕猴"},{"孙悟空"}}
  sort.Sort(monkeys)
  fmt.Println(monkeys)

接口和继承比较

  • A结构体继承了B结构体,那么A结构体就自动的继承了B结构体的字段和方法,并且可以直接使用
  • 当A结构体需要扩展功能,同时不希望去破坏继承关系,则可以去实现某个接口即可,
  • 接口是对继承的补充,是like和is的区别
  • 继承解决代码的复用性和可维护性
  • 接口更加灵活,一定程度上实现了解耦

注意项

  • 接口不能创建实例,接口可以指向实现了接口的结构体实例
  • 结构体必须实现所有接口的方法才可以说实现了该接口
  • 接口默认是指针类型,没有初始化会输出nil
  • 空接口可以接收任何类型

全部代码

package main
import (
  "fmt"
  "sort"
)
type Monkey struct {
  Name string
}
func (m *Monkey)climb(){
  fmt.Println(m.Name,"会爬树...")
}
//--------Flyable接口---------
type Flyable interface {
  Fly()
}
//--------Swimmable接口-------
type Swimmable interface {
  Swim()
}
//----------接口继承--------------
type Skills interface {
  Flyable
  Swimmable
  Change()
}
//-----------空接口-----------
type Null interface {
}
//---------不破坏结构体,添加属性--------
type WuKong struct {
  Monkey
  Tool string
}
//---------不破坏继承,扩展行为/方法--------
func (w *WuKong) Fly() {
  fmt.Println("筋斗云,来...")
}
func (w *WuKong) Swim()  {
  fmt.Println("老龙王,俺老孙的金箍棒呢?")
}
func (w *WuKong) Change()  {
  fmt.Println("看我72变...")
}
type MonkeySlice []Monkey
//--------实现Len--------
func (m MonkeySlice) Len() int{
  return len(m)
}
//---------实现Less---------
func (m MonkeySlice) Less(i,j int) bool {
  return m[i].Name < m[j].Name
}
//----------实现Swap---------
func (m MonkeySlice) Swap(i,j int){
  m[i],m[j] = m[j],m[i]
}
func main() {
  //-----------接口体-------
  w := WuKong{}
  w.Name = "孙悟空"
  //-----------使用方法------
  w.climb()
  //-----------使用实现的接口的方法---------
  w.Fly()
  //-----------结构体赋值给接口------------
  var s Skills
  s = &w
  s.Change()
  //----------空接口-------------
  var null Null
  null = w
  wukong := null.(WuKong)
  wukong.Swim()
  //-----------结构体切片排序--------------
  monkeys := MonkeySlice{{"峨眉猴"},{"齐天大圣"},{"金丝猴"},{"六耳猕猴"},{"孙悟空"}}
  sort.Sort(monkeys)
  fmt.Println(monkeys)
}

截图

2020062310470442.png

参考

Go标准库-sort

更多Go相关内容:Go-Golang学习总结笔记

有问题请下方评论,转载请注明出处,并附有原文链接,谢谢!如有侵权,请及时联系。

相关文章
|
4月前
|
存储 Go
Go语言之接口与多态 -《Go语言实战指南》
Go 语言中的接口是实现多态的核心机制,通过一组方法签名定义行为。任何类型只要实现接口的所有方法即视为实现该接口,无需显式声明。本文从接口定义、使用、底层机制、组合、动态行为到工厂模式全面解析其特性与应用,帮助理解 Go 的面向接口编程思想及注意事项(如 `nil` 陷阱)。
137 22
|
4月前
|
存储 JSON Go
Go语言之空接口与类型断言
本文介绍了 Go 语言中空接口(`interface{}`)和类型断言的核心概念及其应用。空接口可存储任意类型数据,适用于通用函数、动态数据结构与 JSON 解析等场景;类型断言用于将接口变量还原为具体类型,推荐使用带 `ok` 的写法以避免程序崩溃。此外,文章通过示例讲解了 `type switch` 类型判断与 JSON 处理技巧,并总结了空接口的注意事项,强调滥用可能导致类型安全性降低。内容深入浅出,帮助开发者灵活运用这些特性。
102 15
|
4月前
|
Go
Go语言接口的定义与实现
Go 语言的接口提供了一种灵活的多态机制,支持隐式实现和抽象编程。本文介绍了接口的基本定义、实现方式、空接口的使用、类型断言以及接口组合等核心概念,并探讨了接口与 nil 的关系及应用场景。通过示例代码详细说明了如何利用接口提升代码的可扩展性和可测试性,总结了接口的关键特性及其在依赖注入、规范定义和多态调用中的重要作用。
170 14
|
4月前
|
算法 Go
Go语言模拟集合类型-《Go语言实战指南》
在 Go 语言中,虽然没有内建的集合(Set)类型,但可以通过 `map` 实现其功能。常用方式包括 `map[T]bool` 和更节省内存的 `map[T]struct{}`。前者以布尔值表示元素存在性,后者利用零内存开销的空结构体。文章介绍了集合的基本操作(添加、删除、判断、遍历),并通过封装示例展示如何创建自定义 Set 类型。这种实现方式适用于去重、唯一标记及集合运算等场景,简洁高效且易于扩展。
|
4月前
|
JSON Go C语言
Go语言之定义结构体(Struct)-《Go语言实战指南》
Go 语言中的结构体(`struct`)是一种复合数据类型,可将多个不同类型的字段组合成一个类型。本文介绍了结构体的基本定义、实例创建方式、字段访问与修改、零值特性、比较规则、嵌套使用及标签功能。通过示例代码详细讲解了如何定义和操作结构体,以及其在 JSON 编码等场景的应用。
|
4月前
|
Go 索引
Go语言数组的定义与操作 - 《Go语言实战指南》
本文介绍了 Go 语言中的数组(Array)相关知识,包括定义、初始化方式(默认、显式、指定索引及自动推导长度)、访问与修改、遍历方法(for 循环和 for range)、值类型特性(复制行为)、多维数组支持以及其与切片的区别。数组是定长且同类型的集合,适合性能敏感场景,但实际开发中更常用动态的切片(slice)。
140 11
|
4月前
|
Go Python
函数的定义与调用 -《Go语言实战指南》
本文介绍了 Go 语言中函数的核心特性与用法,包括基本定义格式、调用方式、多返回值、返回值命名、参数类型简写、可变参数、高阶函数及匿名函数等内容。通过示例代码详细展示了如何定义和使用不同类型的函数,使读者能够全面了解 Go 函数的灵活性与强大功能。
|
9月前
|
Go 开发工具
百炼-千问模型通过openai接口构建assistant 等 go语言
由于阿里百炼平台通义千问大模型没有完善的go语言兼容openapi示例,并且官方答复assistant是不兼容openapi sdk的。 实际使用中发现是能够支持的,所以自己写了一个demo test示例,给大家做一个参考。
|
7月前
|
存储 算法 Go
Go语言实战:错误处理和panic_recover之自定义错误类型
本文深入探讨了Go语言中的错误处理和panic/recover机制,涵盖错误处理的基本概念、自定义错误类型的定义、panic和recover的工作原理及应用场景。通过具体代码示例介绍了如何定义自定义错误类型、检查和处理错误值,并使用panic和recover处理运行时错误。文章还讨论了错误处理在实际开发中的应用,如网络编程、文件操作和并发编程,并推荐了一些学习资源。最后展望了未来Go语言在错误处理方面的优化方向。
|
10月前
|
JSON 前端开发 JavaScript
聊聊 Go 语言中的 JSON 序列化与 js 前端交互类型失真问题
在Web开发中,后端与前端的数据交换常使用JSON格式,但JavaScript的数字类型仅能安全处理-2^53到2^53间的整数,超出此范围会导致精度丢失。本文通过Go语言的`encoding/json`包,介绍如何通过将大整数以字符串形式序列化和反序列化,有效解决这一问题,确保前后端数据交换的准确性。
239 4