标签 Golang 下的文章

也谈Go语言代码包分发

Go语言目前(截至1.0.2版本)尚不支持直接链接.a文件(这里的.a文件指的不是传统静态共享库,而是对golang的非main包build后的产物)。这样一来Go的第三方库包或组织内部的公共代码库包只能以源码的形式分发了。

Go提供了get命令用于获取他人分发的代码包。我们通过get命令既可以获取一些知名代码托管站点上的代码,也可以获取组织内部版本控制服务器上的公共代码。

Go get支持的托管站点包括github、google code、BitBucket以及Launchpad,针对这类情况,我们可以得到“特殊”语法的照顾:

go get github.com/bmizerany/assert
go get bitbucket.org/bmizerany/assert
go get code.google.com/p/assert
go get launchpad.net/assert

由于Go已经“内置”了github、google code等的版本控制工具类型,因此我们无需再做任何额外指定,只需用代码的url(去掉http://)即可。

执行get后,代码会被下载到GOPATH环境变量配置中的第一个路径下的src目录下面。例如:我们的GOPATH=/home/tonybai /goworkspace1:/home/tonybai/goworkspace2,执行go get github.com/bmizerany/assert后,我们将在/home/tonybai/goworkspace1下看到github.com 目录,而assert包在本地的完整路径就是/home/tonybai/goworkspace1/github.com/bmizerany /assert。这样我们在代码中直接import "github.com/bmizerany/assert"即可使用assert这个第三方包了。

在组织内部我们也会有自己的私有公共代码库,一份代码库可能被多个项目所使用。在每个项目中都保存一份公共库代码显然是不利于后续版本升级维护的,这样就需要各个项目统一从同一个地方获取或更新公共库代码。这种情况我们同样可以用go get命令来做。

假设内部使用subversion作为版本控制工具,公共库架设在10.10.12.13/svn0/share/golib。这时我们不能简单地的通 过"go get 10.10.12.13/svn0/share/golib"来获取到代码,我们需要告诉get我们采用哪种版本控制工具,而这种信息的传递是通过在库名称后面加上后缀的方式进行的。比如:

go get "10.10.12.13/svn0/share/golib.svn"

这样在/home/tonybai/goworkspace1下就会出现10.10.12.13/svn0/share/golib.svn目录结构。我 们在代码中可以直接import对应的包,比如import "10.10.12.13/svn0/share/golib.svn/assert"。

通过对get命令特性的了解,我们也可以确定分发的代码包到底应该如何组织。从上面的例子我们可以看出我们分发的代码包结构不需很复杂,直接在库的 repository下建立包目录即可,比如上面例子中库repository为golib,assert就是直接建立在下面的目录,同时也是包名。

go get可自动识别http_proxy环境变量,这样Go也可以通过代理获取外部代码包。

使用外部代码包的项目可以通过go get -u url来更新代码包版本为最新版本。

也谈Go语言声明语法

一直在从事C语言服务端应用开发,对C的变量声明语法早已烂熟于胸,同时也深知复杂的C变量声明十分晦涩难解。记得若干年前还特意花了一些时间研究理解复 杂C变量声明的方法,记忆中这些方法包括:《C专家编程》中提到的“优先级”规则、right-left规则以及顺时针/螺旋形规则等,幸运地是我们日常 开发中少有使用极为复杂的变量声明(如void (*signal (int signo, void (*func) (int)))(int);),但C语言中这一难点却是事实存在的。

对于我这样的习惯了C变量声明语法的程序员来说,Go的变量声明语法显得极端另类,完全与C语言反其道而行之,心中不由产生一丝厌恶。但随着对Go学习和 使用的深入,我逐渐发现Go的这种声明语法在不经意间解决了复杂声明的理解问题,你无需学习什么"优先级"规则,也无需理会什么“right-left” 规则,你只需按从左到右的顺序阅读代码,再复杂的变量声明也可以很轻易地理解。

Go语言为何要采用这种倒序语法呢?Go的设计者Rob Pike的一篇介绍Go声明语法的文章给出了答案,其中谈到了Go声明语法的设计考量。Go的设计者从C体系之外的语言获得启发:将变量名放在签名,类型说明放在后 面。这样更接近于自然语言,例如:

x: int
p: pointer to int
a: array[3] of int

b: slice of int

在此基础上,Go的设计者用*、[]等符号替换掉上面的冒号和部分关键字使得声明变得短小,也就形成了Go的声明语法:

var x int
var p *int
var a [3]int

var b []int

我们只需从左向右的顺序阅读代码,即可清晰的理解声明的含义,而不需要像C声明语法那样左右符号都要兼顾,螺旋理解。这里面的*、[n]和[]的含义如下:

*some_type:读作 pointer to some_type
[n]some_type: 读作 array[n] of some_type
[]some_type: 读作 slice of some_type

下面我们通过Go与C的对比来进一步理解Go的声明语法。

简单变量声明

                                           Golang
int x;      <–>      var x int //x has the type int
float x;    <–>      var x float64 //x has the type float64
char c;     <–>      var c byte
//x has the type byte

指针变量声明

C                                            Golang
int *x;     <–>      var x *int //x is a pointer to int
int **p;    <–>      var p **int //p is a pointer to pointer to int 

数组/切片变量声明

C                                            Golang
int a[5];     <-->    var a [5]int //a is an array[5] of int
int a[5][3];  <-->    var a [5][3]int  //a is an array[5] of array[3] of int

                                            var s []int //s is a slice of int(C语言中无slice类型)

函数类型变量声明

C                                            Golang
int (*x)(int, int) 类似于   var x func(int, int) int // x has the type "func(int, int) int"
     

Go中函数为first-class类型,其类型的变量等同于C中的函数指针。

复合声明(复杂声明)

C                                            Golang
int *x[5];   <-->       var x [5]*int //x is an array[5] of pointer to int
int (*x[5])(int, int)   类似于  var x [5]func(int, int) int // x is an array[5] of "func(int, int) int" 

                                                var f func(func(int,int) int, int) func(int, int) int //f has the type "func(func(int,int) int, int) func(int, int) int",这是一个函数类型变量,这个函数类型接收三个参数(其中一个参数是func(int, int)函数类型),并返回另外一个函数类型(func(int, int) int)。

void (*signal (int signo, void (*Afunc) (int))) 类似于  var signal func(signo int, Afunc func(int))

有了上面的例子,signal就无需再作解释了,Go的声明语法可以让我们可以很容易的理解复杂的变量声明。但从可读性角度来看较长的声明依旧不利于代码理解。因此我们还是应该通过type定义一些新类型的方式尽量缩短变量声明的长度,例如:

type Handler func(int)
type SignalHandler func(signo int, handler Handler)
var signal SignalHandler

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言精进之路1 Go语言精进之路2 Go语言编程指南
商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats