目录

Go最全大红大紫的-Golang-真的是后端开发中的万能药吗,大牛手把手带你

目录

Go最全大红大紫的 Golang 真的是后端开发中的万能药吗?,大牛手把手带你

https://i-blog.csdnimg.cn/blog_migrate/3f0c0e719fc6ba13cf793934f547bd39.png

https://i-blog.csdnimg.cn/blog_migrate/50ad39425be0f4b82a82d35080c424cf.png

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

func longTask(signal chan int) {

// 不带参数的 for

// 相当于 while 循环

for {

// 接收 signal 通道传值

v := <- signal

// 如果接收值为 1,停止循环

if v == 1 {

break

}

time.Sleep(1 * Second)

}

}

func main() {

// 声明通道

sig := make(chan int)

// 异步调用 longTask

go longTask(sig)

// 等待 1 秒钟

time.Sleep(1 * time.Second)

// 向通道 sig 传值

sig <- 1

// 然后 longTask 会接收 sig 传值,终止循环

}

复制代码

面向接口编程

Go 语言不是严格的面向对象编程(OOP),它采用的是面向接口编程(IOP),是相对于 OOP 更先进的编程模式。作为 OOP 体系的一部分,IOP 更加强调规则和约束,以及接口类型方法的约定,从而让开发人员尽可能的关注更抽象的程序逻辑,而不是在更细节的实现方式上浪费时间。很多大型项目采用的都是 IOP 的编程模式。如果想了解更多面向接口编程,请查看 “码之道” 个人技术博客的往期文章 《为什么说 TypeScript 是开发大型前端项目的必备语言》 ,其中有关于面向接口编程的详细讲解。

Go 语言跟 TypeScript 一样,也是采用鸭子类型的方式来校验接口继承。下面这个例子可以描述 Go 语言的鸭子类型特性。

// 定义 Animal 接口

interface Animal {

Eat() // 声明 Eat 方法

Move() // 声明 Move 方法

}

// ==== 定义 Dog Start ====

// 定义 Dog 类

type Dog struct {

}

// 实现 Eat 方法

func (d *Dog) Eat() {

fmt.Printf(“Eating bones”)

}

// 实现 Move 方法

func (d *Dog) Move() {

fmt.Printf(“Moving with four legs”)

}

// ==== 定义 Dog End ====

// ==== 定义 Human Start ====

// 定义 Human 类

type Human struct {

}

// 实现 Eat 方法

func (h *Human) Eat() {

fmt.Printf(“Eating rice”)

}

// 实现 Move 方法

func (h *Human) Move() {

fmt.Printf(“Moving with two legs”)

}

// ==== 定义 Human End ====

复制代码

可以看到,虽然 Go 语言可以定义接口,但跟 Java 不同的是,Go 语言中没有显示声明接口实现(Implementation)的关键词修饰语法。在 Go 语言中,如果要继承一个接口,你只需要在结构体中实现该接口声明的所有方法。这样,对于 Go 编译器来说你定义的类就相当于继承了该接口。在这个例子中,我们规定,只要既能吃(Eat)又能活动(Move)的东西就是动物(Animal)。而狗(Dog)和人(Human)恰巧都可以吃和动,因此它们都被算作动物。这种依靠实现方法匹配度的继承方式,就是鸭子类型:如果一个动物看起来像鸭子,叫起来也像鸭子,那它一定是鸭子。这种鸭子类型相对于传统 OOP 编程语言显得更灵活。但是,后面我们会讨论到,这种编程方式会带来一些麻烦。

错误处理

Go 语言的错误处理是臭名昭著的啰嗦。这里先给一个简单例子。

package main

import “fmt”

func isValid(text string) (valid bool, err error){

if text == “” {

return false, error(“text cannot be empty”)

}

return text == “valid text”, nil

}

func validateForm(form map[string]string) (res bool, err error) {

for _, text := range form {

valid, err := isValid(text)

if err != nil {

return false, err

}

if !valid {

return false, nil

}

}

return true, nil

}

func submitForm(form map[string]string) (err error) {

if res, err := validateForm(form); err != nil || !res {

return error(“submit error”)

}

fmt.Printf(“submitted”)

return nil

}

func main() {

form := map[string]string{

“field1”: “”,

“field2”: “invalid text”,

“field2”: “valid text”,

}

if err := submitForm(form); err != nil {

panic(err)

}

}

复制代码

虽然上面整个代码是虚构的,但可以从中看出,Go 代码中充斥着 if err := ...; err != nil { ... } 之类的错误判断语句。这是因为 Go 语言要求开发者自己管理错误,也就是在函数中的错误需要显式抛出来,否则 Go 程序不会做任何错误处理。因为 Go 没有传统编程语言的 try/catch 针对错误处理的语法,所以在错误管理上缺少灵活度,导致了 “ err 满天飞” 的局面。

不过,辩证法则告诉我们,这种做法也是有好处的。第一,它强制要求 Go 语言开发者从代码层面来规范错误的管理方式,这驱使开发者写出更健壮的代码;第二,这种显式返回错误的方式避免了 “ try/catch 一把梭”,因为这种 “一时爽” 的做法很可能导致 Bug 无法准确定位,从而产生很多不可预测的问题;第三,由于没有 try/catch 的括号或额外的代码块,Go 程序代码整体看起来更清爽,可读性较强。

其他

Go 语言肯定还有很多其他特性,但笔者认为以上的特性是 Go 语言中比较有特色的,是区分度比较强的特性。Go 语言其他一些特性还包括但不限于如下内容。

  • 编译迅速
  • 跨平台
  • defer 延迟执行
  • select/case 通道选择
  • 直接编译成可执行程序
  • 非常规依赖管理(可以直接引用 Github 仓库作为依赖,例如 import "github.com/crawlab-team/go-trace"
  • 非常规日期格式(格式为 “2006-01-02 15:04:05”,你没看错,据说这就是 Golang 的创始时间!)

优缺点概述


前面介绍了 Go 的很多语言特性,想必读者已经对 Golang 有了一些基本的了解。其中的一些语言特性也暗示了它相对于其他编程语言的优缺点。Go 语言虽然现在很火,在称赞并拥抱 Golang 的同时,不得不了解它的一些缺点。

这里笔者不打算长篇大论的解析 Go 语言的优劣,而是将其中相关的一些事实列举出来,读者可以自行判断。以下是笔者总结的 Golang 语言特性的不完整优缺点对比列表。

| 特性 | 优点 | 缺点 |

| — | — | — |

| 语法简单 | 提升开发效率,节省时间 | 难以处理一些复杂的工程问题 |

| 天然支持并发 | 极大减少异步编程的难度,提高开发效率 | 不熟悉通道和协程的开发者会有一些学习成本 |

| 类型系统 |

  • Go 语言是静态类型,相对于动态类型语言更稳定和可预测
  • IOP 鸭子类型比严格的 OOP 语言更简洁

|

  • 没有继承、抽象、静态、动态等特性
  • 缺少泛型,导致灵活性降低
  • 难以快速构建复杂通用的框架或工具

|

| 错误处理 | 强制约束错误管理,避免 “ try/catch 一把梭” | 啰嗦的错误处理代码,充斥着 if err := ... |

| 编译迅速 | 这绝对是一个优点 | 怎么可能是缺点? |

| 非常规依赖管理 |

  • 可以直接引用发布到 Github 上的仓库作为模块依赖引用,省去了依赖托管的官方网站
  • 可以随时在 Github 上发布 Go 语言编写的第三方模块
  • 自由的依赖发布意味着 Golang 的生态发展将不受官方依赖托管网站的限制

| 严重依赖 Github,在 Github 上搜索 Go 语言模块相对不精准 |

| 非常规日期格式 | 按照 6-1-2-3-4-5(2006-01-02 15:04:05),相对来说比较好记 | 对于已经习惯了 yyyy-MM-dd HH:mm:ss 格式的开发者来说非常不习惯 |

其实,每一个特性在某种情境下都有其相应的优势和劣势,不能一概而论。就像 Go 语言采用的静态类型和面向接口编程,既不缺少类型约束,也不像严格 OOP 那样冗长繁杂,是介于动态语言和传统静态类型 OOP 语言之间的现代编程语言。这个定位在提升 Golang 开发效率的同时,也阉割了不少必要 OOP 语法特性,从而缺乏快速构建通用工程框架的能力(这里不是说 Go 无法构建通用框架,而是它没有 Java、C# 这么容易)。另外,Go 语言 “奇葩” 的错误处理规范,让 Go 开发者们又爱又恨:可以开发出更健壮的应用,但同时也牺牲了一部分代码的简洁性。要知道,Go 语言的设计理念是为了 “大道至简”,因此才会在追求高性能的同时设计得尽可能简单。

无可否认的是,Go 语言内置的并发支持是非常近年来非常创新的特性,这也是它被分布式系统广泛采用的重要原因。同时,它相对于动辄编译十几分钟的 Java 来说是非常快的。此外,Go 语言没有因为语法简单而牺牲了稳定性;相反,它从简单的约束规范了整个 Go 项目代码风格。因此,**“快”(Fast)、“简”(Concise)、“稳”(Robust)**是 Go 语言的设计目的。我们在对学习 Golang 的过程中不能无脑的接纳它的一切,而是应该根据它自身的特性判断在实际项目应用中的情况。

适用场景


经过前文关于 Golang 各个维度的讨论,我们可以得出结论: Go 语言并不是后端开发的万能药 。在实际开发工作中,开发者应该避免在任何情况下无脑使用 Golang 作为后端开发语言。相反, 工程师在决定技术选型之前应该全面了解候选技术(语言、框架或架构)的方方面面,包括候选技术与业务需求的切合度,与开发团队的融合度,以及其学习、开发、时间成本等因素 。笔者在学习了包括前后端的一些编程语言之后,发现它们各自有各自的优势,也有相应的劣势。 如果一门编程语言能广为人知,那它绝对不会是一门糟糕语言 。因此,笔者不会断言 “XXX 是世界上最好的语言“,而是给读者分享个人关于特定应用场景下技术选型的思路。当然,本文是针对 Go 语言的技术文,接下来笔者将分享一下个人认为 Golang 最适合的应用场景。

分布式应用

Golang 是非常适合在分布式应用场景下开发的。分布式应用的主要目的是尽可能多的利用 计算资源和网络带宽 ,以求最大化系统的整体性能和效率,其中重要的需求功能就是并发(Concurrency)。而 Go 是支持 高并发异步编程 方面的佼佼者。前面已经提到,Go 语言内置了 协程(Goroutine) 通道(Channel) 两大并发特性,这使后端开发者进行异步编程变得非常容易。Golang 中还内置了 sync ,包含 Mutex (互斥锁)、 WaitGroup (等待组)、 Pool (临时对象池)等接口,帮助开发者在并发编程中能更安全的掌控 Go 程序的并发行为。Golang 还有很多 分布式应用开发工具 ,例如分布式储存系统(Etcd、SeaweedFS)、RPC 库(gRPC、Thrift)、主流数据库 SDK(mongo-driver、gnorm、redigo)等。这些都可以帮助开发者有效的构建分布式应用。

网络爬虫

稍微了解网络爬虫的开发者应该会听说过 Scrapy,再不济也是 Python。市面上关于 Python 网络爬虫的技术书籍数不胜数,例如崔庆才的 《Python 3 网络开发实战》 和韦世东的《Python 3 网络爬虫宝典 用 Python 编写的高性能爬虫框架 Scrapy》,自发布以来一直是爬虫工程师的首选。

不过,由于近期 Go 语言的迅速发展,越来越多的爬虫工程师注意到用 Golang 开发网路爬虫的巨大优势。其中,用 Go 语言编写的 Colly 爬虫框架,如今在 Github 上已经有 13k+ 标星。其简洁的 API 以及高效的采集速度,吸引了很多爬虫工程师,占据了爬虫界一哥 Scrapy 的部分份额。前面已经提到,Go 语言内置的并发特性让严重依赖网络带宽的爬虫程序更加高效,很大的提高了数据采集效率。另外,Go 语言作为静态语言,相对于动态语言 Python 来说有更好的约束下,因此健壮性和稳定性都更好。

后端 API

Golang 有很多优秀的后端框架,它们大部分都非常完备的支持了现代后端系统的各种功能需求:RESTful API、路由、中间件、配置、鉴权等模块。而且用 Golang 写的后端应用性能很高,通常有非常快的响应速度。笔者曾经在开源爬虫管理平台 Crawlab 中用 Golang 重构了 Python 的后端 API,响应速度从之前的几百毫秒优化到了几十毫秒甚至是几毫秒,用实践证明 Go 语言在后端性能方面全面碾压动态语言。Go 语言中比较知名的后端框架有 Gin 、 Beego 、 Echo 、 Iris 。

当然,这里并不是说用 Golang 写后端就完全是一个正确的选择。笔者在工作中会用到 Java 和 C#,用了各自的主流框架(SpringBoot 和 .Net Core)之后,发现这两门传统 OOP 语言虽然语法啰嗦,但它们的语法特性很丰富,特别是泛型,能够轻松应对一些逻辑复杂、重复性高的业务需求。因此,笔者认为在考虑用 Go 来编写后端 API 时候,可以提前调研一下 Java 或 C#,它们在写后端业务功能方面做得非常棒。

https://i-blog.csdnimg.cn/blog_migrate/d436e35208bd1e899bc3df95c0ccc001.png

https://i-blog.csdnimg.cn/blog_migrate/3ea20311257f45f35c73789e1915434c.png

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

法特性很丰富,特别是泛型,能够轻松应对一些逻辑复杂、重复性高的业务需求。因此,笔者认为在考虑用 Go 来编写后端 API 时候,可以提前调研一下 Java 或 C#,它们在写后端业务功能方面做得非常棒。

[外链图片转存中…(img-fzT7asFr-1715509970959)]

[外链图片转存中…(img-2u6TUnZ7-1715509970959)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!