Go 并发实战核心编程【三】接口最佳实践

简介: Go 并发实战核心编程【三】接口最佳实践

接口最佳实践



sort包学习


1. sort对整形切片或者数组排序


平时写的整形切片排序:


var sl = []int{2, 4, 3, 1}
 sort.Ints(sl)
 fmt.Println(sl)


输出:[1 2 3 4]

我们看sort源码中有专门针对整形切片实现排序,例如:


sli := sort.IntSlice{2, 5, 3, 1}
 sli.Sort()
 fmt.Println(sli)


输出:[1 2 3 5]

我们看下源码实现:


// IntSlice attaches the methods of Interface to []int, sorting in increasing order.
type IntSlice []int
func (x IntSlice) Len() int           { return len(x) }
func (x IntSlice) Less(i, j int) bool { return x[i] < x[j] }
func (x IntSlice) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
// Sort is a convenience method: x.Sort() calls Sort(x).
func (x IntSlice) Sort() { Sort(x) }


我们发现IntSlice类型实现了三个方法,而且最后Sort方法调用了函数Sort,这个函数就是sort包中真正核心意义上的排序函数,底层是快速排序实现的,我们可以看下:


// 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))
}


我们可以继续定位到quickSort,但是这里重点介绍接口最佳实践,所以不再深入快速排序内部逻辑,大家下去自行研究。


我们看到Sort函数参数是Interface接口,而这个接口定义如下:


type Interface interface {
 Len() int
 Less(i, j int) bool
 Swap(i, j int)
}

啊哈,看到这里我们发现IntSlice是实现了Interface接口,所以它可以调用上述Sort函数实现整形切片排序。


但是它这个排序是从小到大排序的,那如果从大到小实现排序呢?给各位留个思考题哈。


2. sort对结构体排序


因为对结构体的切片排序已经有相关函数实现了,比如看如下结构体:


// 学生
type StudentStruct struct {
 Name string
 Age int
}
type StudentSlice []StudentStruct
func (ss StudentSlice) Len() int {
 return len(ss)
}
// Less 按照年龄排序
func (ss StudentSlice) Less(i, j int) bool {
 return ss[i].Age < ss[j].Age
}
func (ss StudentSlice) Swap(i, j int) {
 ss[i], ss[j] = ss[j], ss[i]
}


用sort包中SliceStable函数实现结构体切片排序:


var students StudentSlice
 for i:=0; i<10; i++ {
  ss := StudentStruct{
   Name: fmt.Sprintf("姓名:%d", i),
   Age: rand.Intn(100),
  }
  students = append(students, ss)
 }
 sort.SliceStable(students, func(i, j int) bool {
  return students[i].Age < students[j].Age
 })
 for _, v:=range students {
  fmt.Println(v)
 }


输出:

{姓名:9 0}

{姓名:5 18}

{姓名:6 25}

{姓名:7 40}

{姓名:2 47}

{姓名:8 56}

{姓名:3 59}

{姓名:0 81}

{姓名:4 81}

{姓名:1 87}


我们看到按照年龄已经排序了,但是如果我们要实现自己的排序规则怎么办呢?

答案很简单,自己实现接口:


type StudentSlice []StudentStruct
func (ss StudentSlice) Len() int {
 return len(ss)
}
// Less 按照姓名从大到小排序
func (ss StudentSlice) Less(i, j int) bool {
 return ss[i].Name > ss[j].Name
}
func (ss StudentSlice) Swap(i, j int) {
 ss[i], ss[j] = ss[j], ss[i]
}
func main() {
 var students StudentSlice
 for i:=0; i<4; i++ {
  ss := StudentStruct{
   Name: fmt.Sprintf("姓名:%d", i),
   Age: rand.Intn(100),
  }
  students = append(students, ss)
 }
 fmt.Println("排序前")
 for _, v:=range students {
  fmt.Println(v)
 }
 fmt.Println("排序后")
 sort.Sort(students)
 for _, v:=range students {
  fmt.Println(v)
 }
}


输出:


排序前

{姓名:0 81}

{姓名:1 87}

{姓名:2 47}

{姓名:3 59}

排序后

{姓名:3 59}

{姓名:2 47}

{姓名:1 87}

{姓名:0 81}


我们看到排序已经是按照我们自己的排序规则排完序了,赞哦!


3. 小结


面向接口编程是一种很牛班的技术,它对底层设计者和开发者能力要求极高,所以一般复杂的底层infra建设都是有公司的大牛们担任,他们定义好接口之后对于技术小白来说你只要按照人家大牛的接口定义实现相应的方法即可,其他底层复杂的逻辑交给大牛们实现。当然如果有一天你写方法写累了,也想成为大牛搞搞底层建设,那么别着急,平时的日子里需要积累,相信吧,快乐的那一天将会来临!

相关文章
|
14天前
|
存储 Rust Go
Go nil 空结构体 空接口有什么区别?
本文介绍了Go语言中的`nil`、空结构体和空接口的区别。`nil`是预定义的零值变量,适用于指针、管道等类型;空结构体大小为0,多个空结构体实例指向同一地址;空接口由`_type`和`data`字段组成,仅当两者均为`nil`时,空接口才为`nil`。
Go nil 空结构体 空接口有什么区别?
|
8天前
|
数据采集 监控 Java
go语言编程学习
【11月更文挑战第3天】
24 7
|
6天前
|
Go 调度 开发者
探索Go语言中的并发模式:goroutine与channel
在本文中,我们将深入探讨Go语言中的核心并发特性——goroutine和channel。不同于传统的并发模型,Go语言的并发机制以其简洁性和高效性著称。本文将通过实际代码示例,展示如何利用goroutine实现轻量级的并发执行,以及如何通过channel安全地在goroutine之间传递数据。摘要部分将概述这些概念,并提示读者本文将提供哪些具体的技术洞见。
|
14天前
|
Unix Linux Go
go进阶编程:Golang中的文件与文件夹操作指南
本文详细介绍了Golang中文件与文件夹的基本操作,包括读取、写入、创建、删除和遍历等。通过示例代码展示了如何使用`os`和`io/ioutil`包进行文件操作,并强调了错误处理、权限控制和路径问题的重要性。适合初学者和有经验的开发者参考。
|
17天前
|
并行计算 安全 Go
Go语言的并发特性
【10月更文挑战第26天】Go语言的并发特性
8 1
|
22天前
|
Java 大数据 Go
Go语言:高效并发的编程新星
【10月更文挑战第21】Go语言:高效并发的编程新星
46 7
|
27天前
|
安全 Go 调度
探索Go语言的并发模式:协程与通道的协同作用
Go语言以其并发能力闻名于世,而协程(goroutine)和通道(channel)是实现并发的两大利器。本文将深入了解Go语言中协程的轻量级特性,探讨如何利用通道进行协程间的安全通信,并通过实际案例演示如何将这两者结合起来,构建高效且可靠的并发系统。
|
25天前
|
安全 程序员 Go
深入浅出Go语言的并发之道
在本文中,我们将探索Go语言如何优雅地处理并发编程。通过对比传统多线程模型,我们将揭示Go语言独特的goroutine和channel机制是如何简化并发编程,并提高程序的效率和稳定性。本文不涉及复杂的技术术语,而是用通俗易懂的语言,结合生动的比喻,让读者能够轻松理解Go语言并发编程的核心概念。
|
6天前
|
存储 JSON 监控
Viper,一个Go语言配置管理神器!
Viper 是一个功能强大的 Go 语言配置管理库,支持从多种来源读取配置,包括文件、环境变量、远程配置中心等。本文详细介绍了 Viper 的核心特性和使用方法,包括从本地 YAML 文件和 Consul 远程配置中心读取配置的示例。Viper 的多来源配置、动态配置和轻松集成特性使其成为管理复杂应用配置的理想选择。
23 2