Go希望成为互联网时代的C语言。
多数系统级语言(包括Java和C#)的根本编程哲学来源于C++,将C++的面向对象进一步发扬光大。但是Go语言的设计者却有不同的看法,他们认为C++ 真的没啥好学的,值得学习的是C语言。C语言经久不衰的根源是它足够简单。因此,Go语言也要足够简单!
互联网时代的C语言需要考虑哪些关键问题呢?
首先,并行与分布式支持。多核化和集群化是互联网时代的典型特征。作为一个互联网时代的C语言,必须要让这门语言操作多核计算机与计算机集群如同操作单机一样容易。
其次,软件工程支持。工程规模不断扩大是产业发展的必然趋势。单机时代语言可以只关心问题本身的解决,而互联网时代的C语言还需要考虑软件品质保障和团队协作相关的话题。
最后,编程哲学的重塑。计算机软件经历了数十年的发展,形成了面向对象等多种学术流派。什么才是最佳的编程实践?
1、
并发执行的“执行体”是个抽象的概念,在操作系统层面有多个概念与之对应,比如操作系统自己掌管的进程(process)、进程内的线程(thread)以及进程内的协程(coroutine,也叫轻量级线程)。
/*
进程拥有自己独立的堆和栈,既不共享堆,亦不共享栈,进程由操作系统调度。
线程拥有自己独立的栈和共享的堆,共享堆,不共享栈,线程亦由操作系统调度(标准线程是的)。
协程和线程一样共享堆,不共享栈,协程由程序员在协程的代码里显示调度。
协程和线程的区别是:协程避免了无意义的调度,由此可以提高性能,但也因此,程序员必须自己承担调度的责任,同时,协程也失去了标准线程使用多CPU的能力。
*/
“执行体间的通信”。执行体间的通信包含几个方式:
执行体之间的互斥与同步
执行体之间的消息传递
“互斥与同步”。当执行体之间存在共享资源(一般是共享内存)时,为保证内存访问逻辑的确定性,需要对访问该共享资源的相关执行体进行互斥。当多个执行体之间的逻辑存在时序上的依赖时,也往往需要在执行体之间进行同步。互斥与同步是执行体间最基础的交互方式。
“执行体之间的消息传递”。在并发编程模型的选择上,有两个流派,一个是共享内存模型,一个是消息传递模型。多数传统语言选择了前者,少数语言选择后者,其中选择“消息传递模型”的最典型代表是Erlang语言。业界有专门的术语叫“Erlang风格的并发模型”,其主体思想是两点:一是“轻量级的进程(Erlang中‘进程’这个术语就是我们上面说的‘执行体’)”,二是“消息乃进程间通信的唯一方式”。当执行体之间需要相互传递消息时,通常需要基于一个消息队列(message queue)或者进程邮箱(process mail box)这样的设施进行通信。
Go语言推荐采用“Erlang风格的并发模型”的编程范式,尽管传统的“共享内存模型”仍然被保留,允许适度地使用。在Go语言中内置了消息队列的支持,只不过它叫通道(channel)。两个goroutine之间可以通过通道来进行交互。
2、
/*
应该说强类型/弱类型和动态类型/静态类型还是有一些微妙的区别的。
静态类型语言是指在编译时变量的数据类型即可确定的语言,多数静态类型语言要求在使用变量之前必须声明数据类型,某些具有类型推导能力的现代语言可能能够部分减轻这个要求.
动态类型语言是在运行时确定数据类型的语言。变量使用之前不需要类型声明,通常变量的类型是被赋值的那个值的类型。
强类型语言是一旦变量的类型被确定,就不能转化的语言。实际上所谓的貌似转化,都是通过中间变量来达到,原本的变量的类型肯定是没有变化的。
弱类型语言则反之,一个变量的类型是由其应用上下文确定的。比如语言直接支持字符串和整数可以直接用 + 号搞定。当然,在支持运算符重载的强类型语言中也能通过外部实现的方式在形式上做到这一点,不过这个是完全不一样的内涵
通常的说,java/python都算是强类型的,而VB/Perl/C都是弱类型的.
不过相比于动态/静态语言的分类,强类型/弱类型更多的是一个相对的概念。
*/
多数软件需要一个团队共同去完成,在团队协作的过程中,人们需要建立统一的交互语言来降低沟通的成本。规范化体现在多个层面,如:
代码风格规范
错误处理规范
包管理
契约规范(接口)
单元测试规范
功能开发的流程规范
Go语言很可能是第一个将代码风格强制统一的语言。
3、
计算机软件经历了数十年的发展,形成了多种学术流派,有面向过程编程、面向对象编程、函数式编程、面向消息编程等,这些思想究竟孰优孰劣,众说纷纭。
C语言是纯过程式的,这和它产生的历史背景有关。Java语言则是激进的面向对象主义推崇者,典型表现是它不能容忍体系里存在孤立的函数。而Go语言没有去否认任何一方,而是用批判吸收的眼光,将所有编程思想做了一次梳理,融合众家之长,但时刻警惕特性复杂化,极力维持语言特性的简洁,力求小而精。
从编程范式的角度来说,Go语言是变革派,而不是改良派。对于C++、Java和C#等语言为代表的面向对象(OO)思想体系,Go语言总体来说持保守态度,有限吸收。
首先,Go语言反对函数和操作符重载(overload),而C++、Java和C#都允许出现同名函数或操作符,只要它们的参数列表不同。虽然重载解决了一小部分面向对象编程(OOP)的问题,但同样给这些语言带来了极大的负担。而Go语言有着完全不同的设计哲学,既然函数重载带来了负担,并且这个特性并不对解决任何问题有显著的价值,那么Go就不提供它。
其次,Go语言支持类、类成员方法、类的组合,但反对继承,反对虚函数(virtual function)和虚函数重载。
确切地说,Go也提供了继承,只不过是采用了组合的文法来提供:
type Foo struct {
Base
...
}
func (foo *Foo) Bar() {
...
}
再次,Go语言也放弃了构造函数(constructor)和析构函数(destructor)。
由于Go语言中没有虚函数,也就没有vptr,支持构造函数和析构函数就没有太大的价值。本着“如果一个特性并不对解决任何问题有显著的价值,那么Go就不提供它”的原则,构造函数和析构函数就这样被Go语言的作者们干掉了。
在放弃了大量的OOP特性后,Go语言送上了一份非常棒的礼物:接口(interface)。
Go语言的非侵入式接口,看似只是做了很小的文法调整,实则影响深远:
其一,Go语言的标准库再也不需要绘制类库的继承树图。你只需要知道这个类实现了哪些方法,每个方法是啥含义就足够了。
其二,不用再纠结接口需要拆得多细才合理。
其三,不用为了实现一个接口而专门导入一个包,而目的仅仅是引用其中的某个接口的定义。在Go语言中,只要两个接口拥有相同的方法列表,那么它们就是等同的,可以相互赋值。
END:
除了OOP外,近年出现了一些小众的编程哲学,Go语言对这些思想亦有所吸收。例如,Go
语言接受了函数式编程的一些想法,支持匿名函数与闭包。再如,Go语言接受了以Erlang语言为
代表的面向消息编程思想,支持goroutine和通道,并推荐使用消息而不是共享内存来进行并发编
程。总体来说,Go语言是一个非常现代化的语言,精小但非常强大。