到目前为止,我做过不下于10次关于Go的讲座,大多数的主题都会与“设计哲学”这样的话题有关。之所 以这样,是因为我对自己的定位是Go语言的“传教士”,而不是“培训师”。我的出发点在于引起大家对Go的 关注与兴趣,至于如何去一步步学习Go语言的语法知识,我相信兴趣是最好的老师。现今我们学习的平台足够 强大,只要你真的很有兴趣,就一定能够学好Go语言。
Go语言是非常简约的语言。简约的意思是少而 精。Go语言极力追求语言特性的最小化,如果某个语法特性只是少些几行代码,但对解决实际问题的难度不会 产生本质的影响,那么这样的语法特性就不会被加入。Go语言更关心的是如何解决程序员开发上的心智负担。 如何减少代码出错的机会,如何更容易写出高品质的代码,是Go设计时极度关心的问题。
Go语言也是 非常追求自然(nature)的语言。Go不只是提供极少的语言特性,并极力追求语言特性最自然的表达,也就是 这些语法特性被设计成恰如多少人期望的那样,尽量避免惊异。事实上Go语言的语法特性上的争议是非常之少 的。这些也让Go语言的入门门槛变得非常低。
今天我的话题重心是关于Go语言编程范式的流派问题。 这仍然是关于“设计哲学”方面的。到目前为止,大家可能听过的编程范式主要如下:
过程式(代表:C)
面向对象(代表:Java、C#)
面向消息(代表:Erlang)
函数式(代表:Haskell、Erlang)
过程式编程的代表概念是过程(函数)。这是一个非常古老的流派,基本上所有语言都有过程式的影子。 但是比较纯粹的过程式的主流语言比较少,通常比较古老,C是其中最典型的代表。
面向对象编程是目 前广为接受、影响极其深远的流派。面向对象有很多概念:如类、方法、属性、重载、多态(虚函数)、构造 和析构、继承等等。Java、C#是其中最典型的代表。Go语言支持面向对象,但将特性最小化。Go语言中有结构 体(类似面向对象中的类),结构体可以有方法,这就是Go对面向对象支持的所有内容。Go语言的面向对象特 征少得可怜。结构体是构成复合对象的基础,只要有组合,通常就由结构体,像C这样的过程式语言,照样有 结构体。所以Go身上没有多少面向对象的烙印,Go 甚至反对继承,拒绝提供继承语法。
面向消息编程 是个比较小众的编程流派,因为分布式与并发编程的强烈诉求而崛起。面向消息编程的主体思想是推荐基于消 息而不是基于锁和共享内存进行并发编程。Erlang语言是面向消息编程的代表。Go语言中有面向消息的影子。 因为Go语言中有channel,可以让执行体(goroutine)之间相互发送消息。但channel只是Go语言的基础语法 特性,Go并没有杜绝锁和共享内存,所以它并不能算面向消息编程流派。
函数式编程也是一个小众的 流派,尽管历史非常悠久。函数式编程中有些概念如:闭包、柯里化、变量不可变等。Haskell、Erlang都是 这个流派的代表。函数式编程之所以小众,个人认为最重要的原因,是理论基础不广为人知。我们缺乏面向函 数式编程的数据结构学。因为变量不可变,数据结构学需要用完全不同思维方式来表达。比如在传统命令式的 编程方式中,数组是最简单的基础数据结构,但函数式编程中,数组这样的数据结构很难提供(修改数组的一 个元素成本太高,Erlang语言中数组这个数据结构很晚才引入,用tree来模拟数组)。Go语言除了支持闭包外 ,没有太多函数式的影子。
Go语言有以上每一流派的影子,但都只是把这些流派的最基础的概念吸收 ,这些特性很基础,很难作为一个流派的关键特征来看。所以从编程范式上来说,个人认为Go语言不属于以上 任何流派。如果非要说一个流派,Go语言类似C++,应该算“多范式”流派的。C++是主流语言中,几乎是唯一 一门大力宣扬多范式编程理念的语言。C++主要支持的编程范式是过程式编程、面向对象编程、泛型编程(我 们上面没有把泛型编程列入讨论的流派之中)。C++对这些流派的主要特性支持都很完整,说“多范式”名副 其实。但Go不一样的是,每个流派的特性支持都很基础,这些特性只能称之为功能,并没有形成范式。
Go语言在吸收这些流派精华的基础上,开创了自己独特的编程风格:一种基于连接与组合的语言。
连接,指的是组件的耦合方式,也就是组件是如何被串联起来的。组合,是形成复合对象的基础。连 接与组合都是语言中非常平凡的概念,但Go语言恰恰是在平凡之中见神奇。
让我们从Unix谈起。Go语 言与Unix、C语言有着极深的渊源。Go语言的领袖们参与甚至主导了Unix和C语言的设计。Ken Thompson 甚至 算得上Unix和C语言的鼻祖。Go语言亦深受Unix和C语言的设计哲学影响。
在Unix世界里,组件就是应 用程序(app),每个app可大体抽象为:
输入:stdin(标准输入), params(命令行参数)
输出:stdout(标准输出)
协议:text (data stream)
不同的应用程序(app)如何连接?答案是:管道(pipeline)。在Unix世界中大家对这样的东西已经很熟 悉了:
app1 params1 | app2 params2
通过管道(pipeline),可以将一个应用程序的输 出(stdout)转换为另一个应用程序的输入(stdin)。更为神奇的一点,是这些应用程序是并行执行的。 app1每产生一段输出,立即会被app2所处理。所以管道(pipeline)称得上是最古老,同时也是极其优秀的并 行设施,简单而强大。
需要注意的是,Unix世界中不同应用程序直接是松散耦合的。上游app的输出是 xml还是json,下游app需要知晓,但并无任何强制的约束。同一输出,不同的下游app,对协议的理解甚至都 可能并不相同。例如,上游app输出一段xml文本,对于某个下游app来说,是一颗dom树,但对linecount程序 来说只是一个多行的文本,对于英文单词词频统计程序来说,是一篇英文文章。
以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索编程
, app低内存
, 面向对象
, go
, 语言
, 编程语言
, 语言编程
, goroutine
, 范式
, go语言
, go语言编程
, 组合输出
, 特性
流派
,以便于您获取更多的相关知识。