闲聊Golang对C语言的改进

看到标题,大家可能会奇怪,为什么将Golang与C语言进行比较?这里主要有三方面的原因,一方面,可以说Golang和C都是源于同样的理念设计的编程语言,上一篇文章有说过,UNIX创始人之一Ken Thompson是Golang的设计者,同时,他也是C语言设计者之一,他深知C语言存在的问题和影响其开发效率的因素,希望在Golang上得以改善;其次,Golang设计之初就希望成为和C/C++一样的系统语言,执行效率应当与C/C++相媲美,但是要有强大的快速开发能力;最后,Go语言的语法和C语言一样,简单却强大。


内存管理

Golang在C语言的基础上添加了内存管理机制,这使得C语言开发中让人头大的各种内存问题得以解决。Golang初始的几个版本内存管理机制被人诟病,垃圾回收会导致程序停顿,但是现在Golang的内存管理已经相当完善。然而,Golang提供内存管理机制的同时。依然保留了C语言的指针变量类型,这是为什么?


Golang对普通变量采用复制的方式进行使用,而指针是将原始对象的地址进行传递,例如函数传参,普通变量会进行形参向实参的拷贝,函数内部对实参的修改不会影响到函数外的变量,而指针变量只是传递地址,函数内部对实参的修改会直接改变函数外的变量。


保留C语言这一概念,为我们的编程带来了极大地灵活性,C语言编程中有一条简单的规则,如果是基本类型(int,float等)建议使用变量,除非需要对变量进行修改;如果使用复合类型(结构体等),如果不是需要深拷贝的场合,建议使用指针,因为这些类型的变量一般占用内存空间比较大,如果使用变量,会多次复制,影响程序性能。Golang保留了这一概念,就让我们可以按照自己的需要选择合适的方式——使用变量还是指针,代码设计的灵活性更大,改善代码性能的方式也更简单。


语句的简洁性

Golang的语句比C语言更加简洁,如定义并初始化变量,

C语言中

int a = 0;


Golang中

a := 0


除了不需要分号,a变量之前未定义,使用:=进行赋值,就是定义变量a且赋值为0,至于a的数据类型,Golang进行了自动推断,由于我们使用整形0进行赋值,所以a就是整形的变量。


编码风格编译阶段检查

Golang对一些编码风格在编译时会进行检查,这样,代码的风格和质量在语法层面上就已经进行了统一。例如,没有使用的import,编译阶段会当做编译错误;代码块左大括号要求与最接近的上一行代码同行,也就是说

func Foo() {   //正确


func foo()    //编译错误


Golang为了方便大家解决这类错误,提供了gofmt工具,运行gofmt直接就会对代码格式进行修正。


不使用动态链接库

Golang不支持动态链接库,Golang编译只会生成一个对应的可执行文件,引用第三方包,使用go get直接拉取源码并统一编译。带来的好处就是Golang的项目部署极其简单,可执行文件只有一个,配置好配置文件,资源安排好,直接运行即可。


具备包体系

Golang引入了包体系,更方便代码结构的控制和引用第三方资源。C语言没有包的概念,所以之前文章提到,我们需要自己组织好代码的位置,防止概念混乱。


面向对象

Golang可以进行面向对象编程,Golang在面向对象方面采取了和C++,Python等相同的理念,Golang提供了面向对象的机制,但是也可以面向过程编程,Golang不限制你使用的编程思想。


Golang的面向对象语法非常简单,派生采用了Has-a的方式,没有提供Is-a的方式,这有两方面原因,一方面,在C语言中,如果进行派生,我们采用一个结构体包含另一个结构体的方式,也就是只能采用Has-a的方式;另外,Is-a的派生方式经常存在问题,如果父类的接口发生变化,经常会直接影响子类的接口也要进行调整,Has-a的方式,父类作为子类的成员变量存在,父类相当于封装在自己的类定义下,代码的变异不容易扩散。


Golang提供了interface,这也是C语言没有的。另外Golang的interface更加易用,不需要显式指定一个类实现了哪个interface,只要是一个类实现了interface中的所有方法,他就可以被认为是这个interface的实现。


至于封装,很简单,首字母大写的全局变量,方法和全局函数是公有的,而首字母小写的全局变量,方法和全局函数是包内可访问的。


复合类型

Golang中的复合类型主要有数组,slice,map和结构体。数组是只读的list,slice则是可变的list,map提供了键值对的结构,结构体是数据的打包。可以看到,Golang没有其他语言的各种容器,泛型等,但是提供的复合类型却足够使用。


type关键字

type和C语言中typedef宏的作用类似,对一个类型进行重命名,但是Golang中,你会发现,定义一个结构体的语法

type FooStruct struct {

    ........

}


还有定义interface的语法

type FooInterface interface {

    ........

}


与其说这是定义,不如说也是进行了一种派生(重新命名了没有成员的struct类型和没有方法的interface类型),而事实上,所有类型都可以作为interface{}使用,类似于C语言中的void类型,但是使用时Golang会要求进行类型断言(Type Assertion),也就是显式的类型转换。不得不惊叹Golang语法简洁背后的严谨。


goroutine机制

Golang被极度赞扬的是它的异步机制,也就是goroutine,如何启动一个异步处理,很简单,将处理封装到函数,然后调用函数时在前面加上go,如

go Foo()


除去语法上的简洁,goroutine是一个协程,也就是比线程更节省资源,一个线程中可以有多个协程,而且goroutine被分配到多个CPU上运行,是真正意义上的并发。


丰富的标准库和第三方资源

Golang的标准库十分强大,甚至于包含了Web开发的接口,模板等等,这些都是C语言不可比拟的,经过几年的发展,Golang也拥有了大量的使用人群,所以第三方资源日趋丰富和完善。


以上就是Golang在C基础上的一些进步,总的说来,经过一段时间对Golang的使用,感受非常好。从Golang可以看到很多C语言的影子,但是很多C开发时作为编码规范和思想的东西,在Golang中已经将其作为语法进行了规范和限制,减少了编码时需要考虑的问题量,同时保留了C语言的灵活性,Golang丰富的标准库和第三方资源,增加了使用Golang进行开发的手段。


但是,不得不承认,Golang不适合作为入门级的编程语言,Golang中语法的很多闪光点,需要结合多种编程语言的对比才能发现,如果你有丰富的编程经验,使用Golang时会发现,当时关注的编码问题,Golang都已经考虑到了,这时你会感叹Golang的设计。毕竟作为新生代的编程语言主力,不应该再出现老一辈语言的问题了,取长补短,正是Golang应该做的。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值