Go 语言接口及使用接口实现链表插入(上)

简介: 1. 接口定义1.1 空接口1.2 实现单一接口1.3 接口多方法实现2. 多态2.1 为不同数据类型的实体提供统一的接口2.2 多接口的实现3. 系统接口调用

1. 接口定义


  • Interface 类型可以定义一组方法,不需要实现,并且不能包含任何的变量,称之为接口
  • 接口不需要显示的实现,只需要一个变量,含有接口类型中的所有方法,那么这个变量就实现了这个接口,如果一个变量含有多个interface 类型的方法,那么这个变量就实现了多个接口
  • 接口又称为动态数据类型,在进行接口使用的的时候,会将接口对位置的动态类型改为所指向的类型
    会将动态值改成所指向类型的结构体
  • 每个接口由数个方法组成,接口的定义格式如下:

其中参数列表和返回值列表中的参数变量名可以省略

type 接口类型名 interface{
    方法名1( 参数列表1 ) 返回值列表1
    方法名2( 参数列表2 ) 返回值列表2
}
  • 自定义接口步骤
    ① 定义接口
    ② 定义结构体
    ③ 接口实现(绑定结构体)
    ④ 定义接口变量,初始化结构体,调用接口实现功能


1.1 空接口


空接口就相当于一个空指针


package main
import "fmt"
//定义空接口
type Test interface{}
func main() {
  //声明接口方法1
  var t Test
  fmt.Printf("t的类型: %T, t的值: %v\n", t, t)
  //声明接口方法2
  var a interface{}
  var b int
  a = b
  fmt.Printf("a的类型: %T, a的值: %v\n", a, a)
}
//输出结果如下
t的类型: <nil>, t的值: <nil>
a的类型: int, a的值: 0


1.2 实现单一接口


结构体使用接口打印信息


package main
import "fmt"
type Student struct {
  Name  string
  Age   int
  Score float32
}
//接口定义:接口是功能的抽象,不需要实现
type Test interface {
  Print()
}
//指针类型实现接口
func (p *Student) Print() {
  fmt.Printf("name:[%s]\n", p.Name)
  fmt.Printf("age:[%d]\n", p.Age)
  fmt.Printf("score:[%f]\n", p.Score)
}
//值类型实现接口
/*
func (p Student) Print() {
  fmt.Printf("name:[%s]\n", p.Name)
  fmt.Printf("age:[%d]\n", p.Age)
  fmt.Printf("score:[%f]\n", p.Score)
}
*/
func main() {
  //声明接口变量
  var t Test
  //结构体初始化
  var stu Student = Student{
    Name:  "zhangsan",
    Age:   18,
    Score: 90,
  }
  //把结构体赋值给接口
  t = &stu
  //接口功能
  t.Print()
}
//输出结果如下
name:[zhangsan]
name:[18]
name:[90.000000]


1.3 接口多方法实现


package main
import "fmt"
type Student struct {
  Name  string
  Age   int
  Score float32
}
//接口定义:接口是功能的抽象,不需要实现
type Test interface {
  Print()
  Sleep()
}
//接口的实现
func (p *Student) Print() {
  fmt.Printf("name:[%s]\n", p.Name)
  fmt.Printf("age:[%d]\n", p.Age)
  fmt.Printf("score:[%f]\n", p.Score)
}
//接口中包含多个方法,如果要使用此接口就要实现接口中包含的所有方法
func (p *Student) Sleep() {
  fmt.Println("正在睡眠~")
}
func main() {
  //声明接口变量
  var t Test
  //结构体初始化
  var stu Student = Student{
    Name:  "zhangsan",
    Age:   18,
    Score: 90,
  }
  //把结构体赋值给接口
  t = &stu
  //接口功能
  t.Print()
  t.Sleep()
}
//输出结果如下
name:[zhangsan]
name:[18]
name:[90.000000]
正在睡眠~


  • 示例,在电脑上定义一个USB接口,实现鼠标、U盘、风扇的功能


package main
import "fmt"
//定义电脑
type Computer struct {
  Brand string  //品牌
  Price float32 //价格
}
//定义USB接口
type USB interface {
  mouse()
  store()
  fan()
}
//接口功能实现
func (c Computer) mouse() {
  fmt.Println("鼠标")
}
func (c Computer) store() {
  fmt.Println("U盘")
}
func (c Computer) fan() {
  fmt.Println("风扇")
}
func main() {
  //初始化结构体
  var com Computer
  //初始化接口
  var usb USB
  com.Brand = "thinkpad"
  com.Price = 5000
  //接口调用
  usb = com
  usb.mouse()
  usb.fan()
  usb.store()
}
//输出结果如下
鼠标
风扇
U盘


2. 多态


  • 对于同一个接口,赋予给不同的结构体,使用相同的方法而产生出不同的操作,称之为多态。


2.1 为不同数据类型的实体提供统一的接口


package main
import "fmt"
//父结构体
type Persion struct {
  Name string
  Age  int
}
//学生子结构体
type Student struct {
  Persion
  Score float32
}
//教师子结构体
type Teacher struct {
  Persion
  Class int
}
//接口定义:接口时功能的抽象,不需要实现
type Test interface {
  Print()
  Sleep()
}
//学生结构体的实现
func (p *Student) Print() {
  fmt.Printf("name:[%s]\n", p.Name)
  fmt.Printf("age:[%d]\n", p.Age)
  fmt.Printf("Score:[%f]\n", p.Score)
}
//教师结构体的实现
func (p *Teacher) Print() {
  fmt.Printf("name:[%s]\n", p.Name)
  fmt.Printf("age:[%d]\n", p.Age)
  fmt.Printf("Class:[%d]\n", p.Class)
}
//接口中包含多个方法,如果要使用此接口就要实现接口中包含的所有方法
func (p *Student) Sleep() {
  fmt.Println("正在睡眠~")
}
func (p *Teacher) Sleep() {
  fmt.Println("正在休息~")
}
func main() {
  //声明接口变量
  var t Test
  //学生初始化
  var stu Student
  stu.Name = "zhangsan"
  stu.Age = 18
  stu.Score = 90
  //教师初始化
  var tea Teacher
  tea.Name = "lisi"
  tea.Age = 25
  tea.Class = 3
  //学生接口功能调用实现
  t = &stu
  t.Print()
  t.Sleep()
  fmt.Println("----------------------------")
  //教师接口功能调用实现
  t = &tea
  t.Print()
  t.Sleep()
}
//输出结果如下
name:[zhangsan]
age:[18]
Score:[90.000000]
正在睡眠~
----------------------------
name:[lisi]
age:[25]
Class:[3]
正在休息~


2.2 多接口的实现


package main
import "fmt"
//接口1
type Test1 interface {
  Print()
}
//接口2
type Test2 interface {
  Sleep()
}
//结构体
type Student struct {
  Name  string
  Age   int
  Score float32
}
//接口1实现
func (s Student) Print() {
  fmt.Printf("name:[%s]\n", s.Name)
}
//接口2实现
func (s Student) Sleep() {
  fmt.Println("正在睡眠")
}
func main() {
  //接口1变量
  var t1 Test1
  //接口2变量
  var t2 Test2
  //初始化结构体
  var stu Student = Student{
    Name:  "zhangsan",
    Age:   18,
    Score: 90,
  }
  //调用接口实现功能
  t1 = stu
  t1.Print()
  t2 = stu
  t2.Sleep()
}
//输出结果如下
name:[zhangsan]
正在睡眠


3. 系统接口调用


  • 示例

使用接口进行排序


package main
import (
    "fmt"
    "math/rand"
    "sort"
)
//结构体
type Student struct {
    Name  string
    Age   int
    Score float32
}
//切片
type StudentArray []Student
//go语言提供了sort 接口。使用接口里的方法即可
//实现sort接口
func (sa StudentArray) Len() int {
    return len(sa)
} //获取切片长度
func (sa StudentArray) Less(i, j int) bool {
    return sa[i].Name > sa[j].Name
} //两数比大小
func (sa StudentArray) Swap(i, j int) {
    sa[i], sa[j] = sa[j], sa[i]
} //两数交换
func main() {
    //Student 切片
    var stus StudentArray
    //生成10个结构体,放入切片中
    for i := 0; i < 10; i++ {
        var stu Student = Student{
            Name:  fmt.Sprintf("stu%d", rand.Intn(100)),
            Age:   rand.Intn(120),
            Score: rand.Float32() * 100,
        }
        //结构体元素存入到切片中
        stus = append(stus, stu)
    }
    //遍历
    for _, v := range stus {
        fmt.Println(v)
    }
    fmt.Println("--------------------------")
    //排序
    sort.Sort(stus)
    //遍历
    for _, v := range stus {
        fmt.Println(v)
    }
}
相关文章
|
5天前
|
JSON 测试技术 Go
零值在go语言和初始化数据
【7月更文挑战第10天】本文介绍在Go语言中如何初始化数据,未初始化的变量会有对应的零值:bool为`false`,int为`0`,byte和string为空,pointer、function、interface及channel为`nil`,slice和map也为`nil`。。本文档作为指南,帮助理解Go的数据结构和正确使用它们。
53 22
零值在go语言和初始化数据
|
5天前
|
JSON Java Go
Go 语言性能优化技巧
在Go语言中优化性能涉及数字字符串转换(如用`strconv.Itoa()`代替`fmt.Sprintf()`)、避免不必要的字符串到字节切片转换、预分配切片容量、使用`strings.Builder`拼接、有效利用并发(`goroutine`和`sync.WaitGroup`)、减少内存分配、对象重用(`sync.Pool`)、无锁编程、I/O缓冲、正则预编译和选择高效的序列化方法。这些策略能显著提升代码执行效率和系统资源利用率。
42 13
|
1天前
|
Cloud Native Java Go
为什么要学习Go语言?
GO logo的核心理念,即简单胜于复杂。使用现代斜体无衬线字体与三条简单的运动线相结合,形成一个类似于快速运动的两个轮子的标记,传达速度和效率。字母的圆形暗示了GO地鼠的眼睛,创造了一个熟悉的形状,让标记和吉祥物很好地搭配在一起。
12 4
|
5天前
|
设计模式 Go
Go语言设计模式:使用Option模式简化类的初始化
在Go语言中,面对构造函数参数过多导致的复杂性问题,可以采用Option模式。Option模式通过函数选项提供灵活的配置,增强了构造函数的可读性和可扩展性。以`Foo`为例,通过定义如`WithName`、`WithAge`、`WithDB`等设置器函数,调用者可以选择性地传递所需参数,避免了记忆参数顺序和类型。这种模式提升了代码的维护性和灵活性,特别是在处理多配置场景时。
41 8
|
5天前
|
存储 Go
go语言中fmt格式化包和内置函数汇总
【7月更文挑战第10天】本文介绍fmt包和`Errorf`用于创建格式化的错误消息。`fmt`包还涉及一些接口,如`Formatter`、`GoStringer`、`ScanState`、`Scanner`和`Stringer`,支持自定义格式化和输入/输出处理。
17 1
|
5天前
|
Go
go语言中格式化输出的占位符
【7月更文挑战第10天】`fmt` 包在 Go 语言中用于格式化输出,包括不同类型的占位符:%v(默认格式)、%+v(带字段名的结构体)、%#v(Go语法表示)、%T(类型表示)、%%(百分号)。布尔值用%t,整数有%b、%c、%d、%o、%q、%x、%X和%U。浮点数和复数用%b、%e、%E、%f、%g、%G。字符串和字节切片用%s、%q、%x、%X。指针用%p。占位符可配合+、-、#、空格和0进行调整。宽度和精度控制输出格式,例如 %.4g 控制小数精度。Go 没有 `%u`,但无符号整数默认打印为正数。运算符包括逻辑、比较、加减、乘除、移位、按位和按位异或等。
17 1
|
7天前
|
存储 Go 索引
在go语言中自定义泛型的变长参数
【7月更文挑战第8天】在Go语言中,由于官方1.18以前的版本不支持泛型,可以通过空接口和反射模拟泛型。泛型适用于通用数据结构和函数,虽牺牲了一些性能,但提高了代码复用和类型安全性。
41 1
|
3天前
|
安全 Go
Go语言map并发安全,互斥锁和读写锁谁更优?
Go并发编程中,`sync.Mutex`提供独占访问,适合读写操作均衡或写操作频繁的场景;`sync.RWMutex`允许多个读取者并行,适用于读多写少的情况。明智选择锁可提升程序性能和稳定性。示例展示了如何在操作map时使用这两种锁。
6 0
|
3天前
|
安全 Go 开发者
Go语言map并发安全使用的正确姿势
在Go并发编程中,由于普通map不是线程安全的,多goroutine访问可能导致数据竞态。为保证安全,可使用`sync.Mutex`封装map或使用从Go 1.9开始提供的`sync.Map`。前者通过加锁手动同步,后者内置并发控制,适用于多goroutine共享。选择哪种取决于具体场景和性能需求。
6 0
|
3天前
|
存储 安全 Java
Go语言中的map为什么默认不是并发安全的?
Go语言的map默认不保证并发安全,以优化性能和简洁性。官方建议在需要时使用`sync.Mutex`保证安全。从Go 1.6起,并发读写map会导致程序崩溃,鼓励开发者显式处理并发问题。这样做的哲学是让代码更清晰,并避免不必要的性能开销。
4 0