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建设都是有公司的大牛们担任,他们定义好接口之后对于技术小白来说你只要按照人家大牛的接口定义实现相应的方法即可,其他底层复杂的逻辑交给大牛们实现。当然如果有一天你写方法写累了,也想成为大牛搞搞底层建设,那么别着急,平时的日子里需要积累,相信吧,快乐的那一天将会来临!

相关文章
|
6月前
|
Linux Go iOS开发
Go语言100个实战案例-进阶与部署篇:使用Go打包生成可执行文件
本文详解Go语言打包与跨平台编译技巧,涵盖`go build`命令、多平台构建、二进制优化及资源嵌入(embed),助你将项目编译为无依赖的独立可执行文件,轻松实现高效分发与部署。
1037 162
|
5月前
|
监控 算法 NoSQL
Go 微服务限流与熔断最佳实践:滑动窗口、令牌桶与自适应阈值
🌟蒋星熠Jaxonic:Go微服务限流熔断实践者。分享基于滑动窗口、令牌桶与自适应阈值的智能防护体系,助力高并发系统稳定运行。
Go 微服务限流与熔断最佳实践:滑动窗口、令牌桶与自适应阈值
|
6月前
|
存储 前端开发 JavaScript
Go语言实战案例-项目实战篇:编写一个轻量级在线聊天室
本文介绍如何用Go语言从零实现一个轻量级在线聊天室,基于WebSocket实现实时通信,支持多人消息广播。涵盖前后端开发、技术选型与功能扩展,助你掌握Go高并发与实时通信核心技术。
765 158
|
7月前
|
数据采集 数据挖掘 测试技术
Go与Python爬虫实战对比:从开发效率到性能瓶颈的深度解析
本文对比了Python与Go在爬虫开发中的特点。Python凭借Scrapy等框架在开发效率和易用性上占优,适合快速开发与中小型项目;而Go凭借高并发和高性能优势,适用于大规模、长期运行的爬虫服务。文章通过代码示例和性能测试,分析了两者在并发能力、错误处理、部署维护等方面的差异,并探讨了未来融合发展的趋势。
664 0
|
7月前
|
数据采集 Go API
Go语言实战案例:使用context控制协程取消
本文详解 Go 语言中 `context` 包的使用,通过实际案例演示如何利用 `context` 控制协程的生命周期,实现任务取消、超时控制及优雅退出,提升并发程序的稳定性与资源管理能力。
398 152
|
5月前
|
Java 编译器 Go
【Golang】(5)Go基础的进阶知识!带你认识迭代器与类型以及声明并使用接口与泛型!
好烦好烦好烦!你是否还在为弄不懂Go中的泛型和接口而烦恼?是否还在苦恼思考迭代器的运行方式和意义?本篇文章将带你了解Go的接口与泛型,还有迭代器的使用,附送类型断言的解释
266 3
|
7月前
|
负载均衡 监控 Java
微服务稳定性三板斧:熔断、限流与负载均衡全面解析(附 Hystrix-Go 实战代码)
在微服务架构中,高可用与稳定性至关重要。本文详解熔断、限流与负载均衡三大关键技术,结合API网关与Hystrix-Go实战,帮助构建健壮、弹性的微服务系统。
734 1
微服务稳定性三板斧:熔断、限流与负载均衡全面解析(附 Hystrix-Go 实战代码)
|
7月前
|
安全 Go 开发者
Go语言实战案例:使用sync.Mutex实现资源加锁
在Go语言并发编程中,数据共享可能导致竞态条件,使用 `sync.Mutex` 可以有效避免这一问题。本文详细介绍了互斥锁的基本概念、加锁原理及实战应用,通过构建并发安全的计数器演示了加锁与未加锁的区别,并封装了一个线程安全的计数器结构。同时对比了Go中常见的同步机制,帮助开发者理解何时应使用 `Mutex` 及其注意事项。掌握 `Mutex` 是实现高效、安全并发编程的重要基础。
|
并行计算 安全 Go
Go语言中的并发编程:掌握goroutines和channels####
本文深入探讨了Go语言中并发编程的核心概念——goroutine和channel。不同于传统的线程模型,Go通过轻量级的goroutine和通信机制channel,实现了高效的并发处理。我们将从基础概念开始,逐步深入到实际应用案例,揭示如何在Go语言中优雅地实现并发控制和数据同步。 ####
|
存储 Go 开发者
Go语言中的并发编程与通道(Channel)的深度探索
本文旨在深入探讨Go语言中并发编程的核心概念和实践,特别是通道(Channel)的使用。通过分析Goroutines和Channels的基本工作原理,我们将了解如何在Go语言中高效地实现并行任务处理。本文不仅介绍了基础语法和用法,还深入讨论了高级特性如缓冲通道、选择性接收以及超时控制等,旨在为读者提供一个全面的并发编程视角。
336 50