2024年最新大红大紫的 Golang 真的是后端开发中的万能药吗?,程序员如何自我学习和成长

img
img

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

需要这份系统化的资料的朋友,可以添加戳这里获取

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

Go 语言相对于其他传统热门编程语言来说,有很多优点,特别是其高效编译速度天然并发特性,让其成为快速开发分布式应用的首选语言。Go 语言是静态类型语言,也就是说 Go 语言跟 Java、C# 一样需要编译,而且有完备的类型系统,可以有效减少因类型不一致导致的代码质量问题。因此,Go 语言非常适合构建对稳定性灵活性均有要求的大型 IT 系统,这也是很多大型互联网公司用 Golang 重构老代码的重要原因:传统的静态 OOP 语言(例如 Java、C#)稳定性高但缺乏灵活性;而动态语言(例如 PHP、Python、Ruby、Node.js)灵活性强但缺乏稳定性。因此,“熊掌和鱼兼得” 的 Golang,受到开发者们的追捧是自然而然的事情,毕竟,“天下苦 Java/PHP/Python/Ruby 们久矣“。

不过,Go 语言并不是没有缺点。用辩证法的思维方式可以推测,Golang 的一些突出特性将成为它的双刃剑。例如,Golang 语法简单的优势特点将限制它处理复杂问题的能力。尤其是 Go 语言缺乏泛型(Generics)的问题,导致它构建通用框架的复杂度大增。虽然这个突出问题在 2.0 版本很可能会有效解决,但这也反映出来明星编程语言也会有缺点。当然,Go 的缺点还不止于此,Go 语言使用者还会吐槽其啰嗦的错误处理方式(Error Handling)、缺少严格约束的鸭子类型(Duck Typing)、日期格式问题等。下面,我们将从 Golang 语言特点开始,由浅入深多维度深入分析 Golang 的优缺点以及项目适用场景。

语言特点


简洁的语法特征

Go 语言的语法非常简单,至少在变量声明、结构体声明、函数定义等方面显得非常简洁。

变量的声明不像 Java 或 C 那样啰嗦,在 Golang 中可以用 := 这个语法来声明新变量。例如下面这个例子,当你直接使用 := 来定义变量时,Go 会自动将赋值对象的类型声明为赋值来源的类型,这节省了大量的代码。

func main() {

valInt := 1 // 自动推断 int 类型

valStr := “hello” // 自动推断为 string 类型

valBool := false // 自动推断为 bool 类型

}

复制代码

Golang 还有很多帮你节省代码的地方。你可以发现 Go 中不会强制要求用 new 这个关键词来生成某个类(Class)的新实例(Instance)。而且,对于公共和私有属性(变量和方法)的约定不再使用传统的 publicprivate 关键词,而是直接用属性变量首字母的大小写来区分。下面一些例子可以帮助读者理解这些特点。

// 定义一个 struct 类

type SomeClass struct {

PublicVariable string // 公共变量

privateVariable string // 私有变量

}

// 公共方法

func (c *SomeClass) PublicMethod() (result string) {

return “This can be called by external modules”

}

// 私有方法

func (c *SomeClass) privateMethod() (result string) {

return “This can only be called in SomeClass”

}

func main() {

// 生成实例

someInstance := SomeClass{

PublicVariable: “hello”,

privateVariable: “world”,

}

}

复制代码

如果你用 Java 来实现上述这个例子,可能会看到冗长的 .java 类文件,例如这样。

// SomeClass.java

public SomeClass {

public String PublicVariable; // 公共变量

private String privateVariable; // 私有变量

// 构造函数

public SomeClass(String val1, String val2) {

this.PublicVariable = val1;

this.privateVariable = val2;

}

// 公共方法

public String PublicMethod() {

return “This can be called by external modules”;

}

// 私有方法

public String privateMethod() {

return “This can only be called in SomeClass”;

}

}

// Application.java

public Application {

public static void main(String[] args) {

// 生成实例

SomeClass someInstance = new SomeClass(“hello”, “world”);

}

}

复制代码

可以看到,在 Java 代码中除了容易看花眼的多层花括号以外,还充斥着大量的 publicprivatestaticthis 等修饰用的关键词,显得异常啰嗦;而 Golang 代码中则靠简单的约定,例如首字母大小写,避免了很多重复性的修饰词。当然,Java 和 Go 在类型系统上还是有一些区别的,这也导致 Go 在处理复杂问题显得有些力不从心,这是后话,后面再讨论。总之,结论就是 Go 的语法在静态类型编程语言中非常简洁。

内置并发编程

Go 语言之所以成为分布式应用的首选,除了它性能强大以外,其最主要的原因就是它天然的并发编程。这个并发编程特性主要来自于 Golang 中的协程(Goroutine)和通道(Channel)。下面是使用协程的一个例子。

func asyncTask() {

fmt.Printf(“This is an asynchronized task”)

}

func syncTask() {

fmt.Printf(“This is a synchronized task”)

}

func main() {

go asyncTask() // 异步执行,不阻塞

syncTask() // 同步执行,阻塞

go asyncTask() // 等待前面 syncTask 完成之后,再异步执行,不阻塞

}

复制代码

可以看到,关键词 go 加函数调用可以让其作为一个异步函数执行,不会阻塞后面的代码。而如果不加 go 关键词,则会被当成是同步代码执行。如果读者熟悉 JavaScript 中的 async/awaitPromise 语法,甚至是 Java、Python 中的多线程异步编程,你会发现它们跟 Go 异步编程的简单程度不是一个量级的!

异步函数,也就是协程之间的通信可以用 Go 语言特有的通道来实现。下面是关于通道的一个例子。

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

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

编程方式会带来一些麻烦。

错误处理

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

package main

[外链图片转存中…(img-SP2giY3x-1715751549419)]
[外链图片转存中…(img-FPLLZgzZ-1715751549420)]
[外链图片转存中…(img-aCB26E65-1715751549420)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

  • 27
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值