注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

峰回路转

近水绕远山,芳草连着天边长

 
 
 

日志

 
 

为什么要使用 Go 语言,Go 语言的优势在哪里?(转载)  

2014-09-24 06:57:45|  分类: 知识天空 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
以下原文转载自知乎每日精选

优势楼上已经说得差不多了,就不累述啦。最近用Go写了点东西,我来唱唱反调,说一些用起来让人很不爽的细节。因为只是周末业余玩一玩,有不对的地方,欢迎指正。
首先,当我需要一个通用链表的时候,在Go里面会大致写成如下的样子:
typeLinkedListstruct{valueinterface{}next*LinkedList}func(next*LinkedList)prepend(valueinterface{})*LinkedList{return&LinkedList{value,next}}functail(valueinterface{})*LinkedList{return&LinkedList{value,nil}}functraverse(item*LinkedList){ifitem==nil{return}fmt.Println(item.value)traverse(item.next)}

上面这段代码有那些别扭的地方呢?
由于Go缺乏meta-programming能力,所以每个节点的value值必须得是interface {}。也就是说链表可以使用下面的方式构造,却不会触发任何的compiler complaint。当这样的需求充斥整个代码间,Go所拥有的静态类型优势也就消失殆尽了。
stupidList:=tail(1991).prepend("CAT").prepend([]byte{1,16})

我们知道在C-families语言里,当链表结束时,都喜欢储存一个特定的指针(NULL),作为约定俗成的终点,同样在函数错误结束时,通常也会有相似的行为。但空指针是一个非常危险的东西,程序员很可能由于忘记检查其是否为NULL而导致程序崩溃,编译器的类型系统也无法对其作出任何的保证,因为程序员可以简单的把空指针声明为任何类型。
在函数错误验证上,Go试图采用multiple return的方式额外返回一个failure解决这个问题,但与返回空指针没有本质区别,都丢掉了编译期检查。实际上在functional programming里早就有相应的解决办法了——Algebraic Types。
以Haskell为例:
-- 用End作为链表终点dataListt=End|Const(Listt)letmy_list=Cons3(Cons6(Cons9End))-- 用Nothing作为函数执行错误或者空的结果search[]=Nothingsearch(h:tails)=ifh==1thenJusthelsesearchtails

其次,Go不支持任何内置算子以及关键字扩展的操作。Go为了避免过度复杂化的设计,实际上使得编码工作变得更加复杂了。
以数学矩阵运算为例,对于矩阵的加操作,我希望可以通过“+”算子来进行,以使它更像是内置的数据类型。在Python里,我可以重载__add__()来完成这一目的,只因为Python/c++等等这些语言都将算子视作函数。我甚至可以通过重载iterator的行为,来达成for遍历器的效果。
foriteminMyType:...

最后,说一说Go体系里最亮眼的goroutine和chan。我觉得并发如果想要做成语言层面的syntactic sugar,都没有办法绕过大并发(massive concurrency)、竞争条件(race condition)、错误处理(error handling)这三个问题;
在大并发方面,Go解决得很好,但本质也就是user-space thread,并不是什么先进的技术;
竞争条件本质上是多个逻辑流对同一片内存进行no-sync操作而产生的。最简单的办法就是避免写操作,比如Haskell中的做法,从根本上取消了变量的重复写操作,竞争条件也就无从说起。但在实际的工作中,总是没有办法避免去操作global-state,也没有办法严格的按照函数式编程去避免side-effects。
那么我们可以稍微退一步,采取一种较弱的模型——保证每个逻辑流都使用独立的内存空间,限定一些受到约束的方法进行沟通。在Erlang中,采用了这种严格的进程内存模型,进程间的交流只能通过传递消息来发生。Go启用Chan通道基本也是这个思路,但出于效率的考量(传递消息需要复制操作),没有做任何强制性的保证,依然可以轻松地对共享内存进行访问。程序的正确性只依赖于程序员正确使用并严格遵守slogan。
do not communicate by sharing memory; instead, share memory by communicating.
另外,相对比于Erlang,Go中对于创建的协程缺乏定位能力(no identity),协程之间也并不是完全独立的(no process isolation)。当系统异常发生(比如除零),往往会当掉整个程序,而不能进行状态回退与恢复操作。
当然在并发和协程错误处理上,毕竟是不同的模型,各有取舍,谁优谁劣因看法而异了。
------
知乎回答里面敲代码不能识别TAB真是太难受了。该at谁来改善下?
— 完 —
本文作者:阿猫

  评论这张
 
阅读(14)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017