蔡超:入门 Go 语言必须跨越的五个思维误区

\u003cblockquote\u003e\n\u003cp\u003e你好,我是蔡超,现在是Mobvista 技术副总裁,前亚马逊(中国)首席软件架构师,极客时间《Go语言从入门到实战》视频课程的作者。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e在2018年的QCon北京全球软件开发大会上,我做了题为《讲给 Java / C++开发者的Go高效编程》的主题演讲,会后跟大家交流,发现许多人对Go语言的学习有需求和热情。但大家的普遍问题就是:不知道该如何高效的入门 Go语言,尤其是有编程基础的开发者,一不小心就会陷入思维的误区。\u003c/p\u003e\n\u003cp\u003e因此,今天我就来梳理一下Go语言入门学习的过程中,你容易产生的五个思维误区,帮你掌握在Go语言与其他编程语言的不同之处。\u003c/p\u003e\n\u003ch2\u003e一、重新思考面向对象程序的设计和实现\u003c/h2\u003e\n\u003cp\u003e首先,你要先理解Go语言面向对象编程是具有特殊性的。当然,“Go是不是支持面向对象“这本身就是一个值得思考的话题,官方文档给出的答案是“Yes and no” 。虽说 Go 语言中是有类型的存在,也允许面向对象的编程风格,但却没有类型层次结构。\u003c/p\u003e\n\u003cp\u003eGo语言中没有对类型继承提供支持,而是通过复合来进行扩展,并通过类型嵌入来简化复合的使用。很多人会把类型嵌入看成是Go中的继承机制,但是类型嵌入并不支持最基本的继承特性:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e子类替换\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e方法重载(override)\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eGo语言中的接口机制与其他语言截然不同,实现接口的类型完全不依赖于接口定义。接口作为方法签名的集合,任何类型的方法集中只要拥有与之对应的全部方法,就表示它实现了该接口。只有深刻理解这些,才能更好发挥Go的生产力特性。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e不支持继承,特殊的接口类型,这些都会要求我们重新思考设计和编程实现。\u003c/strong\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e戳此可获取:\u003ca href=\"https://time.geekbang.org/course/detail/160-84354?utm_term=zeusNOD4R\u0026amp;utm_source=wechat\u0026amp;utm_medium=infoq\u0026amp;utm_campaign=160-onsell\u0026amp;utm_content=0322banner\"\u003eGo语言官方文档 \u003c/a\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2\u003e二、改变传统GC(垃圾收集器)语言的思维模式\u003c/h2\u003e\n\u003cp\u003eGo是一个非常特殊的语言,即追求简单性又追求高效率,Go既内置支持GC(垃圾收集器),又支持指针对内存的直接访问。其他支持GC的语言,比如在Java中,由于希望对开发者可以屏蔽内存管理,所以语言中没有提供指针的直接访问。为了提高数据访问和传递的效率,编程语言根据不同的情况,通过约束采用值传递或引用传递,来减少数据复制。\u003c/p\u003e\n\u003cp\u003e而Go比较简单地统一采用值传递,但提供指针机制,因此用户可以自己来选择数据的传递方式,要引用传递时可以通过传递指针来完成。\u003c/p\u003e\n\u003cp\u003e所以在编码时,你要考虑充分指针,提高数据访问效率,减少内存复制并编写GC友好的代码。\u003c/p\u003e\n\u003ch2\u003e三、重新思考程序的错误处理机制\u003c/h2\u003e\n\u003cp\u003eGo语言的错误处理机制中既不支持现在主流的异常模式,同时也与传统的C程序通过返回值返回错误状态不同,Go语言支持返回多个值,可以同时返回结果和错误状态。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e以下是Java语言示例:\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003etry{\n...\n}catch(XXException e){\n //错误处理\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e以下是Go语言示例:\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003eif v, err = callSomeFn(); err!=nil{\n //错误处理\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eGo的error处理方式一直以来都是争论的焦点,很多开发者认为Go的错误处理机制似乎回到了70年代,使得错误处理代码冗长且重复。而Go的设计者则认为try-catch-finally的结构导致异常处理与控制流程的耦合,从而使程序结构发生了混乱。\u003c/p\u003e\n\u003cp\u003eGo的设计者当初选择返回值这种错误处理机制,而不是try-catch这种机制,主要是考虑到前者适用于大型软件,后者更适合小程序。因此,程序变大的时候,try-catch会让错误处理更加冗长繁琐,也就容易出错。try-catch-finally会怂恿程序员标注过多普通错误,诸如打开文件失败之类的异常,使得程序更加繁琐。\u003c/p\u003e\n\u003cp\u003e这就决定了你必须重新思考错误处理的编程模式,因为这样的代码是Go语言中非常常见的。\u003c/p\u003e\n\u003ch2\u003e四、思考和学习使用CSP并发模型\u003c/h2\u003e\n\u003cp\u003e与主流语言通过共享内存来进行并发控制方式不同,Go语言采用了CSP模式。这是一种用于描述两个独立的并发实体通过共享的通讯 Channel(管道)进行通信的并发模型。很多使用过Erlang等基于Actor模式的程序员,会误认为Go和这些语言的模式是一样的。\u003c/p\u003e\n\u003cp\u003e而实际上,Go的CSP模式与常见的Actor模式(如:Erlang语言就采用了Actor模式)也有不少差异,例如:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e和Actor的直接通讯不同,CSP模式则是通过Channel进行通讯的,更松耦合一些;\u003c/li\u003e\n\u003cli\u003eGo中channel是有容量限制并且独立于处理Groutine,而如Erlang,Actor模式中的mailbox容量是无限的,接收进程也总是被动地处理消息。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cimg src=\"https://static.geekbang.org/infoq/5c94a4211815c.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ccenter/\u003eActor模式和CSP模式区别图\u003c/center\u003e\n\u003cp\u003e所以,要用好Go语言,一定要思考和学习使用CSP来高效的实现我们常见并发任务。\u003c/p\u003e\n\u003ch2\u003e五、理解Goroutine的调度机制\u003c/h2\u003e\n\u003cp\u003eGoroutine 是Go语言的招牌特性之一,较之线程是非常轻量级的。但是,如果你不了解其中的机制,仅仅按照线程的套路来使用,就发挥不出来Goroutine的优势,甚至还会导致很多性能问题。\u003c/p\u003e\n\u003cp\u003eGoroutine有着和Java线程完全不同的调度机制,Java线程模型中线程和KSE(Kernel space Entity)是1:1的关系,一个用户线程对应一个KSE。而Groutine和KSE是多对多的对应关系。虽然,Groutine的调度机制不如,由内核直接调度的线程机制效率那么高,但是由于Groutine间的切换可以不涉及内核级切换,所以代价小很多。\u003c/p\u003e\n\u003cp\u003eCSP并发模型、Goroutine的调度机制是Go语言入门学习的过程中的重点和难点,我会在\u003ca href=\"https://time.geekbang.org/course/intro/160?utm_term=zeusNOD4R\u0026amp;utm_source=wechat\u0026amp;utm_medium=infoq\u0026amp;utm_campaign=160-onsell\u0026amp;utm_content=0322banner\"\u003e《Go语言从入门到实战》进阶篇\u003c/a\u003e中进行详细的讲解,敬请期待。\u003c/p\u003e\n\u003cp\u003e拓展阅读:\u003cbr /\u003e\n\u003ca href=\"https://time.geekbang.org/course/detail/160-84356?utm_term=zeusNOD4R\u0026amp;utm_source=wechat\u0026amp;utm_medium=infoq\u0026amp;utm_campaign=160-onsell\u0026amp;utm_content=0322banner\"\u003e5个步骤,编写你的第一个 Go 程序\u003c/a\u003e\u003c/p\u003e\n

你可能感兴趣的:(蔡超:入门 Go 语言必须跨越的五个思维误区)