golang语言-1-go普及知识

前端之家收集整理的这篇文章主要介绍了golang语言-1-go普及知识前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

Go 语言的官方网站是 golang.org,这个站点采用 Python 作为前端,并且使用 Go 语言自带的工具 godoc 运行在 Google App Engine 上来作为 Web 服务器提供文本内容。在官网的首页有一个功能叫做 Go Playground,是一个 Go 代码的简单编辑器的沙盒,它可以在没有安装 Go 语言的情况下在你的浏览器中编译并运行 Go,它提供了一些示例,其中包括国际惯例 “Hello,World!”。

更多的信息详见 github.com/golang/go,Go 项目 Bug 追踪和功能预期详见github.com/golang/go/issues

谷歌邮件列表 golang-nuts 非常活跃,每天的讨论和问题解答数以百计。

关于 Go 语言在 Google App Engine 的应用,这里有一个单独的邮件列表 google-appengine-go,不过 2 个邮件列表的讨论内容并不是分得很清楚,都会涉及到相关的话题。go-lang.cat-v.org/ 是 Go 语言开发社区的资源站,irc.freenode.net 的#go-nuts 是官方的 Go IRC 频道。

@golang 是 Go 语言在 Twitter 的官方帐号,大家一般使用 #golang 作为话题标签

这里还有一个在 Linked-in 的小组:www.linkedin.com/groups?gid=2524765&trk=myg_ugrp_ovr

Go 编程语言的维基百科:en.wikipedia.org/wiki/Go_(programming_language)

Go 语言相关资源的搜索引擎页面gowalker.org

Go 语言还有一个运行在 Google App Engine 上的 Go Tour,你也可以通过执行命令 go install go-tour.googlecode.com/hg/gotour 安装到你的本地机器上。对于中文读者,可以访问该指南的中文版本,或通过命令go install https://bitbucket.org/mikespook/go-tour-zh/gotour 进行安装。


Go 语言并不是凭空而造的,而是和 C++、Java 和 C# 一样属于 C 系。不仅如此,设计者们还汲取了其它编程语言的精粹部分融入到 Go 语言当中。

在声明和包的设计方面,Go 语言受到 Pascal、Modula 和 Oberon 系语言的影响;在并发原理的设计上,Go 语言从同样受到 Tony Hoare 的 CSP(通信序列进程Communicating Squential Processes)理论影响的 Limbo 和 Newsqueak 的实践中借鉴了一些经验,并使用了和 Erlang 类似的机制。

这是一门完全开源的编程语言,因为它使用 BSD 授权许可,所以任何人都可以进行商业软件的开发而不需要支付任何费用。

尽管为了能够让目前主流的开发者们能够对 Go 语言中的类 C 语言的语法感到非常亲切而易于转型,但是它在极大程度上简化了这些语法,使得它们比 C/C++ 的语法更加简洁和干净。同时,Go 语言也拥有一些动态语言的特性,这使得使用 Python 和 Ruby 的开发者们在使用 Go 语言的时候感觉非常容易上手。

Go 语言的主要目标是将静态语言的安全性和高效性与动态语言的易开发性进行有机结合,达到完美平衡,从而使编程变得更加有乐趣,而不是在艰难抉择中痛苦前行。

因此,Go 语言是一门类型安全和内存安全的编程语言。虽然 Go 语言中仍有指针的存在,但并不允许进行指针运算。

Go 语言的另一个目标是对于网络通信、并发和并行编程的极佳支持,从而更好地利用大量的分布式和多核的计算机,这一点对于谷歌内部的使用来说就非常重要了。设计者通过 goroutine 这种轻量级线程的概念来实现这个目标,然后通过 channel 来实现各个 goroutine 之间的通信。他们实现了分段栈增长和 goroutine 在线程基础上多路复用技术的自动化。

Go 语言中另一个非常重要的特性就是它的构建速度(编译和链接到机器代码的速度),一般情况下构建一个程序的时间只需要数百毫秒到几秒。整个 Go 语言标准库的编译时间一般都在 20 秒以内,其它的常规项目也只需要半秒钟的时间来完成编译工作。

Go 语言还能够在运行时进行反射相关的操作。

使用 go install 能够很轻松地对第三方包进行部署。

Go 语言有一套完整的编码规范,你可以在 Go 语言编码规范 页面进行查看。

它不像 Ruby 那样通过实现过程来定义编码规范。作为一门具有明确编码规范的语言,它要求可以采用不同的编译器如 gc 和 gccgo(第 2.1 节)进行编译工作,这对语言本身拥有更好的编码规范起到很大帮助。

LALR 是 Go 语言的语法标准,你也可以在src/cmd/internal/gc/go.y 中查看到,这种语法标准在编译时不需要符号表来协助解析。


Go 语言从本质上(程序和结构方面)来实现并发编程。

因为 Go 语言没有类和继承的概念,所以它和 Java 或 C++ 看起来并不相同。但是它通过接口(interface)的概念来实现多态性。Go 语言有一个清晰易懂的轻量级类型系统,在类型之间也没有层级之说。因此可以说这是一门混合型的语言。

Go 语言使用静态类型,所以它是类型安全的一门语言,加上通过构建到本地代码,程序的执行速度也非常快。

作为强类型语言,隐式的类型转换是不被允许的,记住一条原则:让所有的东西都是显式的。

Go 语言其实也有一些动态语言的特性(通过关键字 var),所以它对那些逃离 Java 和 .Net 世界而使用 Python、Ruby、PHP 和 JavaScript 的开发者们也具有很大的吸引力。

Go 语言支持交叉编译,比如说你可以在运行 Linux 系统的计算机上开发运行下 Windows 下运行的应用程序。这是第一门完全支持 UTF-8 的编程语言,这不仅体现在它可以处理使用 UTF-8 编码的字符串,就连它的源码文件格式都是使用的 UTF-8 编码。Go 语言做到了真正的国际化!

Go 语言被设计成一门应用于搭载 Web 服务器,存储集群或类似用途的巨型中央服务器的系统编程语言。对于高性能分布式系统领域而言,Go 语言无疑比大多数其它语言有着更高的开发效率。它提供了海量并行的支持,这对于游戏服务端的开发而言是再好不过了。

Go 语言一个非常好的目标就是实现所谓的复杂事件处理(CEP),这项技术要求海量并行支持,高度的抽象化和高性能。当我们进入到物联网时代,CEP 必然会成为人们关注的焦点。

但是 Go 语言同时也是一门可以用于实现一般目标的语言,例如对于文本的处理,前端展现,甚至像使用脚本一样使用它。

值得注意的是,因为垃圾回收和自动内存分配的原因,Go 语言不适合用来开发对实时性要求很高的软件。

面向对象语言中使用的特性 Go 语言都没有支持,但其中的一部分可能会在未来被支持
  • 为了简化设计,不支持函数重载和操作符重载
  • 为了避免在 C/C++ 开发中的一些 Bug 和混乱,不支持隐式转换
  • Go 语言通过另一种途径实现面向对象设计来放弃类和类型的继承
  • 尽管在接口的使用方面可以实现类似变体类型的功能,但本身不支持变体类型
  • 不支持动态加载代码
  • 不支持动态链接
  • 不支持泛型
  • 通过 recoverpanic 来替代异常机制
  • 不支持断言
  • 不支持静态变量

关于 Go 语言开发团队对于这些方面的讨论,你可以通过 Go 常见问题 页面查看。

列举一些 Go 语言的必杀技:
  • 简化问题,易于学习
  • 内存管理,简洁语法,易于使用
  • 快速编译,高效开发
  • 高效执行
  • 并发支持,轻松驾驭
  • 静态类型
  • 标准类库,规范统一
  • 易于部署
  • 文档全面
  • 免费开源

Go 语言开发团队开发了适用于以下操作系统的编译器:

  • Linux
  • FreeBSD
  • Mac OS X(也称为 Darwin)

目前有2个版本的编译器:Go 原生编译器 gc 和非原生编译器 gccgo,这两款编译器都是在类 Unix 系统下工作 。其中,gc 版本的编译器已经被移植到 Windows 平台上,并集成在主要发行版中,你也可以通过安装 MinGW 从而在 Windows 平台下使用 gcc 编译器。这两个编译器都是以单通道的形式工作。

你可以获取以下平台上的 Go 1.4 源码和二进制文件

  • Linux 2.6+:amd64、386 和 arm 架构
  • Mac OS X(Snow Leopard + Lion):amd64 和 386 架构
  • Windows 2000+:amd64 和 386 架构

对于非常底层的纯 Go 语言代码或者包而言,在各个操作系统平台上的可移植性是非常强的,只需要将源码拷贝到相应平台上进行编译即可,或者可以使用交叉编译来构建目标平台的应用程序。但如果你打算使用 cgo 或者类似文件监控系统的软件,就需要根据实际情况进行相应地修改了。

  1. Go 原生编译器 gc:

    主要基于 Ken Thompson 先前在 Plan 9 操作系统上使用的 C 工具链。

    Go 语言的编译器和链接器都是使用 C 语言编写并产生本地代码,Go 不存在自我引导之类的功能。因此如果使用一个有不同指令集的编译器来构建 Go 程序,就需要针对操作系统和处理器架构(32 位操作系统或 64 位操作系统)进行区别对待。

    这款编译器使用非分代、无压缩和并行的方式进行编译,它的编译速度要比 gccgo 更快,产生更好的本地代码,但编译后的程序不能够使用 gcc 进行链接

    编译器目前支持以下基于 Intel 或 AMD 处理器架构的程序构建。

    图2.1 gc 编译器支持的处理器架构

    当你第一次看到这套命名系统的时候你会觉得很奇葩,不过这些命名都是来自于 Plan 9 项目。

     g = 编译器:将源代码编译为项目代码(程序文本)
     l = 链接器:将项目代码链接到可执行的二进制文件(机器代码

    (相关的 C 编译器名称为 6c、8c 和 5c,相关的汇编器名称为 6a、8a 和 5a)

    标记(Flags) 是指可以通过命令行设置可选参数来影响编译器或链接器的构建过程或得到一个特殊的目标结果。

    可用的编译器标记如下:

     flags:
     -I 针对包的目录搜索
     -d 打印声明信息
     -e 不限制错误打印的个数
     -f 打印栈结构
     -h 发生错误时进入恐慌(panic)状态
     -o 指定输出文件名 // 详见第3.4节
     -S 打印产生的汇编代码
     -V 打印编译器版本 // 详见第2.3节
     -u 禁止使用 unsafe 包中的代码
     -w 打印归类后的语法解析树
     -x 打印 lex tokens

    从 Go 1.0.3 版本开始,不再使用 8g,8l 之类的指令进行程序的构建,取而代之的是统一的 go build go install 等命令,而这些指令会自动调用相关的编译器或链接器。

    如果你想获得更深层次的信息,你可以在目录 $GOROOT/src/cmd 下找到编译器和链接器的源代码。Go 语言本身是由 C 语言开发的,而不是 Go 语言(Go 1.5 开始自举)。词法分析程序是 GNU bison,语法分析程序是名为$GOROOT/src/cmd/gc/go.y 的 yacc 文件,它会在同一目录输出 y.tab.{c,h} 文件。如果你想知道更多有关构建过程的信息,你可以在$GOROOT/src/make.bash 中找到。

    大部分的目录都包含了名为 doc.go文件,这个文件提供了更多详细的信息。

  2. gccgo 编译器:

    一款相对于 gc 而言更加传统的编译器,使用 GCC 作为后端。GCC 是一款非常流行的 GNU 编译器,它能够构建基于众多处理器架构的应用程序。编译速度相对 gc 较慢,但产生的本地代码运行要稍微快一点。它同时也提供一些与 C 语言之间的互操作性。

    从 Go 1 版本开始,gc 和 gccgo 在编译方面都有等价的功能

  3. 文件扩展名与包(package):

    Go 语言源文件的扩展名很显然就是 .go

    C 文件使用后缀名 .c,汇编文件使用后缀名 .s。所有的源代码文件都是通过包(packages)来组织。包含可执行代码的包文件在被压缩后使用扩展名.a(AR 文档)。

    Go 语言的标准库(第 9.1 节)包文件在被安装后就是使用这种格式的文件

    注意 当你在创建目录时,文件名称永远不应该包含空格,而应该使用下划线 "_" 或者其它一般符号代替。

环境变量

Go 开发环境依赖于一些操作系统环境变量,你最好在安装 Go 之间就已经设置好他们。如果你使用的是 Windows 的话,你完全不用进行手动设置,Go 将被默认安装在目录c:/go 下。这里列举几个最为重要的环境变量:

  • $GOROOT 表示 Go 在你的电脑上的安装位置,它的值一般都是 $HOME/go,当然,你也可以安装在别的地方。
  • $GOARCH 表示目标机器的处理器架构,它的值可以是 386、amd64 或 arm。
  • $GOOS 表示目标机器的操作系统,它的值可以是 darwin、freebsd、linux 或 windows。
  • $GOBIN 表示编译器和链接器的安装位置,默认是 $GOROOT/bin,如果你使用的是 Go 1.0.3 及以后的版本,一般情况下你可以将它的值设置为空,Go 将会使用前面提到的默认值。

目标机器是指你打算运行你的 Go 应用程序的机器。

Go 编译器支持交叉编译,也就是说你可以在一台机器上构建运行在具有不同操作系统和处理器架构上运行的应用程序,也就是说编写源代码的机器可以和目标机器有完全不同的特性(操作系统与处理器架构)。

为了区分本地机器和目标机器,你可以使用 $GOHOSTOS$GOHOSTARCH 设置目标机器的参数,这两个变量只有在进行交叉编译的时候才会用到,如果你不进行显示设置,他们的值会和本地机器($GOOS$GOARCH)一样。

  • $GOPATH 默认采用和 $GOROOT 一样的值,但从 Go 1.1 版本开始,你必须修改为其它路径。它可以包含多个包含 Go 语言源码文件、包文件和可执行文件的路径,而这些路径下又必须分别包含三个规定的目录:srcpkgbin,这三个目录分别用于存放源码文件、包文件和可执行文件
  • $GOARM 专门针对基于 arm 架构的处理器,它的值可以是 5 或 6,默认为 6。
  • $GOMAXPROCS 用于设置应用程序可使用的处理器个数与核数,

在接下来的章节中,我们将会讨论如何在 Linux、Mac OS X 和 Windows 上安装 Go 语言。在 FreeBSD 上的安装和 Linux 非常类似。开发团队正在尝试将 Go 语言移植到其它例如 OpenBSD、DragonFlyBSD、NetBSD、Plan 9、Haiku 和 Solaris 操作系统上,你可以在这个页面找到最近的动态:Go Porting Efforts

在 Linux 上安装 Go

如果你能够自己下载并编译 Go 的源代码来说是非常有教育意义的,你可以根据这个页面找到安装指南和下载地址:Download the Go distribution

我们接下来也会带你一步步的完成安装过程。

  1. 设置 Go 环境变量

    我们在 Linux 系统下一般通过文件 $HOME/.bashrc 配置自定义环境变量,根据不同的发行版也可能是文件 $HOME/.profile,然后使用 gedit 或 vi 来编辑文件内容

     export GOROOT=$HOME/go

    为了确保相关文件文件系统的任何地方都能被调用,你还需要添加以下内容

     export PATH=$PATH:$GOROOT/bin

    在开发 Go 项目时,你还需要一个环境变量来保存你的工作目录。

     export GOPATH=$HOME/Applications/Go

    $GOPATH 可以包含多个工作目录,取决于你的个人情况。如果你设置了多个工作目录,那么当你在之后使用 go get(远程包安装命令)时远程包将会被安装在第一个目录下。

    在完成这些设置后,你需要在终端输入指令 source .bashrc 以使这些环境变量生效。然后重启终端,输入 go envenv 来检查环境变量是否设置正确。

  2. 安装 C 工具

    Go 的工具链是用 C 语言编写的,因此在安装 Go 之前你需要先安装相关的 C 工具。如果你使用的是 Ubuntu 的话,你可以在终端输入以下指令( 译者注:由于网络环境的特殊性,你可能需要将每个工具分开安装 )。

     sudo apt-get install bison ed gawk gcc libc6-dev make

    你可以在其它发行版上使用 RPM 之类的工具。

  3. 获取 Go 源代码

    官方页面 国内镜像 下载 Go 的源码包到你的计算机上,然后将解压后的目录 go 通过命令移动到 $GOROOT 所指向的位置。

     wget https://storage.googleapis.com/golang/go<VERSION>.src.tar.gz
     tar -zxvf go<VERSION>.src.tar.gz
     sudo mv go $GOROOT
  4. 构建 Go

    在终端使用以下指令来进行编译工作。

     cd $GOROOT/src
     ./all.bash

    在完成编译之后(通常在 1 分钟以内,如果你在 B 型树莓派上编译,一般需要 1 个小时),你会在终端看到如下信息被打印:

    图 2.3 完成编译后在终端打印的信息

    注意事项

    在测试 net/http 包时有一个测试会尝试连接 google.com,你可能会看到如下所示的一个无厘头的错误报告:

     ‘make[2]: Leaving directory `/localusr/go/src/pkg/net’

    如果你正在使用一个带有防火墙的机器,我建议你可以在编译过程中暂时关闭防火墙,以避免不必要的错误

    解决这个问题的另一个办法是通过设置环境变量 $DISABLE_NET_TESTS 来告诉构建工具忽略 net/http 包的相关测试:

     export DISABLE_NET_TESTS=1

    如果你完全不想运行包的测试,你可以直接运行 ./make.bash 来进行单纯的构建过程。

  5. 测试安装

    使用你最喜爱的编辑器来输入以下内容,并保存为文件test.go

    示例 2.1 hello_world1.go

    package main
    
    func main() {
    	println("Hello","world")
    }

    切换相关目录到下,然后执行指令 go run hello_world1.go,将会打印信息:Hello,world

  6. 验证安装版本

    你可以通过在终端输入指令 go version 来打印 Go 的版本信息。

    如果你想要通过 Go 代码在运行时检测版本,可以通过以下例子实现。

    示例 2.2 version.go

    package main
    
    import (
    	"fmt"
    	"runtime"
    )
    
    func main() {
    	fmt.Printf("%s",runtime.Version())
    }

    这段代码将会输出 go1.4.2 或类似字符串。

  7. 更新版本

    你可以在 发布历史 页面查看到最新的稳定版。

    当前最新的稳定版 Go 1 系列于 2012 年 3 月 28 日发布。

    Go 的源代码有以下三个分支:

     - Go release:最新稳定版,实际开发最佳选择
     - Go weekly:包含最近更新的版本,一般每周更新一次
     - Go tip:永远保持最新的版本,相当于内测版

    当你在使用不同的版本时,注意官方博客发布的信息,因为你所查阅的文档可能和你正在使用的版本不相符。

安装目录清单

你的 Go 安装目录($GOROOT)的文件夹结构应该如下所示:

README.md,AUTHORS,CONTRIBUTORS,LICENSE

  • /bin:包含可执行文件,如:编译器,Go 工具
  • /doc:包含示例程序,代码工具,本地文档等
  • /lib:包含文档模版
  • /misc:包含与支持 Go 编辑器有关的配置文件以及 cgo 的示例
  • /os_arch:包含标准库的包的对象文件.a
  • /src:包含源代码构建脚本和标准库的包的完整源代码(Go 是一门开源语言)
  • /src/cmd:包含 Go 和 C 的编译器和命令行脚本

Go 运行时(runtime)

尽管 Go 编译器产生的是本地可执行代码,这些代码仍旧运行在 Go 的 runtime(这部分的代码可以在 runtime 包中找到)当中。这个 runtime 类似 Java 和 .NET 语言所用到的虚拟机,它负责管理包括内存分配、垃圾回收、栈处理、goroutine、channel、切片(slice)、map 和反射(reflection)等等。

runtime 主要由 C 语言编写(Go 1.5 开始自举),并且是每个 Go 包的最顶级包。你可以在目录 $GOROOT/src/runtime 中找到相关内容

垃圾回收器 Go 拥有简单却高效的标记-清除回收器。它的主要思想来源于 IBM 的可复用垃圾回收器,旨在打造一个高效、低延迟的并发回收器。目前 gccgo 还没有回收器,同时适用 gc 和 gccgo 的新回收器正在研发中。使用一门具有垃圾回收功能的编程语言不代表你可以避免内存分配所带来的问题,分配和回收内容都是消耗 cpu 资源的一种行为。

Go 的可执行文件都比相对应的源代码文件要大很多,这恰恰说明了 Go 的 runtime 嵌入到了每一个可执行文件当中。当然,在部署到数量巨大的集群时,较大的文件体积也是比较头疼的问题。但总得来说,Go 的部署工作还是要比 Java 和 Python 轻松得多。因为 Go 不需要依赖任何其它文件,它只需要一个单独的静态文件,这样你也不会像使用其它语言一样在各种不同版本的依赖文件之间混淆。

Go 解释器

因为 Go 具有像动态语言那样快速编译的能力,自然而然地就有人会问 Go 语言能否在 REPL(read-eval-print loop)编程环境下实现。Sebastien Binet 已经使用这种环境实现了一个 Go 解释器,你可以在这个页面找到:https://github.com/sbinet/igo

编辑器和集成开发环境

这些编辑器包含了代码高亮和其它与 Go 有关的一些使用工具:Emacs、Vim、Xcode 6、KD Kate、TextWrangler、BBEdit、McEdit、TextMate、TextPad、JEdit、SciTE、Nano、Notepad++、Geany、SlickEdit、IntelliJ IDEA 和 Sublime Text 2。

你可以将 Linux 的文本编辑器 GEdit 改造成一个很好的 Go 开发工具,详见页面http://gohelp.wordpress.com/

Sublime Text 是一个革命性的跨平台(Linux、Mac OS X、Windows)文本编辑器,它支持编写非常多的编程语言代码。对于 Go 而言,它有一个插件叫做GoSublime支持代码补全和代码模版。

这里还有一些更加高级的 Go 开发工具,其中一些是以插件的形式利用本身是作为开发 Java 的工具。

IntelliJ Idea Plugin 是一个 IntelliJ IDEA 的插件,具有很好的操作体验和代码补全功能

LiteIDE 这是一款专门针对 Go 开发的集成开发环境,在编辑、编译和运行 Go 程序和项目方面都有非常好的支持。同时还包括了对源代码的抽象语法树视图和一些内置工具(此开发环境由国人 vfc 大叔开发)。

GoClipse 是一款 Eclipse IDE 的插件,拥有非常多的特性以及通过 GoCode 来实现代码补全功能

如果你对集成开发环境都不是很熟悉,那就使用 LiteIDE 吧,另外使用 GoClipse 或者 IntelliJ Idea Plugin 也是不错的选择。

代码补全 一般都是通过内置 GoCode 实现的(如:LieteIDE、GoClipse),如果需要手动安装 GoCode,在命令行输入指令go get -u github.com/nsf/gocode 即可(务必事先配置好 Go 环境变量)。

接下来会对这三个集成开发环境做更加详细的说明。

调试器

应用程序的开发过程中调试是必不可少的一个环节,因此有一个好的调试器是非常重要的,可惜的是,Go 在这方面的发展还不是很完善。目前可用的调试器是 gdb,最新版均以内置在集成开发环境 LiteIDE 和 GoClipse 中,但是该调试器的调试方式并不灵活且操作难度较大。

如果你不想使用调试器,你可以按照下面的一些有用的方法来达到基本调试的目的:

  1. 在合适的位置使用打印语句输出相关变量的值(print/printlnfmt.Print/fmt.Println/fmt.Printf)。

  2. fmt.Printf 中使用下面的说明符来打印有关变量的相关信息:

    • %+v 打印包括字段在内的实例的完整信息
    • %#v 打印包括字段和限定类型名称在内的实例的完整信息
    • %T 打印某个类型的完整说明
  3. 使用 panic 语句来获取栈跟踪信息(直到 panic 时所有被调用函数的列表)。

  4. 使用关键字 defer 来跟踪代码执行过程。

构建并运行 Go 程序

在大多数 IDE 中,每次构建程序之前都会自动调用源码格式化工具 gofmt 并保存格式化后的源文件。如果构建成功则不会输出任何信息,而当发生编译时错误时,则会指明源码中具体第几行出现了什么错误,如:a declared and not used。一般情况下,你可以双击 IDE 中的错误信息直接跳转到发生错误的那一行。

如果程序执行一切顺利并成功退出后,将会在控制台输出 Program exited with code 0

从 Go 1 版本开始,使用 Go 自带的更加方便的工具来构建应用程序:

  • go build 编译并安装自身包和依赖包
  • go install 安装自身包和依赖包

格式化代码

Go 开发团队不想要 Go 语言像许多其它语言那样总是在为代码风格而引发无休止的争论,浪费大量宝贵的开发时间,因此他们制作了一个工具:go fmtgofmt)。这个工具可以将你的源代码格式化成符合官方统一标准的风格,属于语法风格层面上的小型重构。遵循统一的代码风格是 Go 开发中无可撼动的铁律,因此你必须在编译或提交版本管理系统之前使用gofmt 来格式化你的代码

尽管这种做法也存在一些争论,但使用 gofmt 后你不再需要自成一套代码风格而是和所有人使用相同的规则。这不仅增强了代码的可读性,而且在接手外部 Go 项目时,可以更快地了解其代码的含义。此外,大多数开发工具也都内置了这一功能

Go 对于代码的缩进层级方面使用 tab 还是空格并没有强制规定,一个 tab 可以代表 4 个或 8 个空格。在实际开发中,1 个 tab 应该代表 4 个空格,而在本身的例子当中,每个 tab 代表 8 个空格。至于开发工具方面,一般都是直接使用 tab 而不替换成空格。

在命令行输入 gofmt –w program.go 会格式化该源文件代码然后将格式化后的代码覆盖原始内容(如果不加参数 -w 则只会打印格式化后的结果而不重写文件);gofmt -w *.go 会格式化并重写所有 Go 源文件gofmt map1 会格式化并重写 map1 目录及其子目录下的所有 Go 源文件

gofmt 也可以通过在参数 -r 后面加入用双引号括起来的替换规则实现代码的简单重构,规则的格式:<原始内容> -> <替换内容>

实例:

gofmt -r '(a) -> a' –w *.go

上面的代码会将源文件中没有意义的括号去掉。

gofmt -r 'a[n:len(a)] -> a[n:]' –w *.go

上面的代码会将源文件中多余的 len(a) 去掉。( 译者注:了解切片(slice)之后就明白这为什么是多余的了

gofmt –r 'A.Func1(a,b) -> A.Func2(b,a)' –w *.go

上面的代码会将源文件中符合条件的函数的参数调换位置。

如果想要了解有关 gofmt 的更多信息,请访问该页面http://golang.org/cmd/gofmt/

生成代码文档

go doc 工具会从 Go 程序和包文件提取顶级声明的首行注释以及每个对象的相关注释,并生成相关文档。

它也可以作为一个提供在线文档浏览的 web 服务器,http://golang.org 就是通过这种形式实现的。

一般用法

  • go doc package 获取包的文档注释,例如:go doc fmt显示使用 godoc 生成fmt 包的文档注释。
  • go doc package/subpackage 获取子包的文档注释,例如:go doc container/list
  • go doc package function 获取某个函数在某个包中的文档注释,例如:go doc fmt Printf显示有关fmt.Printf() 的使用说明。

这个工具只能获取在 Go 安装目录下 .../go/src 中的注释内容。此外,它还可以作为一个本地文档浏览 web 服务器。在命令行输入godoc -http=:6060,然后使用浏览器打开http://localhost:6060 后,你就可以看到本地文档浏览服务器提供的页面

godoc 也可以用于生成非标准库的 Go 源码文件的文档注释(第 9.6 章)。

如果想要获取更多有关 godoc 的信息,请访问该页面http://golang.org/cmd/godoc/(在线版的第三方包godoc 可以使用Go Walker)。

其它工具

Go 自带的工具集主要使用脚本和 Go 语言自身编写的,目前版本的 Go 实现了以下三个工具:

  • go install 是安装 Go 包的工具,类似 Ruby 中的 rubygems。主要用于安装非标准库的包文件,将源代码编译成对象文件
  • go fix 用于将你的 Go 代码从旧的发行版迁移到最新的发行版,它主要负责简单的、重复的、枯燥无味的修改工作,如果像 API 等复杂的函数修改,工具则会给出文件名和代码行数的提示以便让开发人员快速定位并升级代码。Go 开发团队一般也使用这个工具升级 Go 内置工具以及 谷歌内部项目的代码go fix 之所以能够正常工作是因为 Go 在标准库就提供生成抽象语法树和通过抽象语法树对代码进行还原的功能。该工具会尝试更新当前目录下的所有 Go 源文件,并在完成代码更新后在控制台输出相关的文件名称
  • go test 是一个轻量级的单元测试框架

Go 性能说明

根据 Go 开发团队和基本的算法测试,Go 语言与 C 语言的性能差距大概在 10%~20% 之间( 译者注:由于出版时间限制,该数据应为 2013 年 3 月 28 日之前产生 )。虽然没有官方的性能标准,但是与其它各个语言相比已经拥有非常出色的表现。

如果说 Go 语言的执行效率大约比 C++ 慢 20% 也许更有实际意义。保守估计在相同的环境和执行目标的情况下,Go 程序比 Java 或 Scala 应用程序要快上 2 倍,并比这两门语言使用少占用 70% 的内存。在很多情况下这种比较是没有意义的,因为像谷歌这样拥有成千上万台服务器的公司都抛弃 C++ 而开始将 Go 用于生产环境已经足够说明它本身所具有的优势。

时下流行的语言大都是运行在虚拟机上,如:Java 和 Scala 使用的 JVM,C# 和 VB.NET 使用的 .NET CLR。尽管虚拟机的性能已经有了很大的提升,但任何使用 JIT 编译器和脚本语言解释器的编程语言(Ruby、Python、Perl 和 JavaScript)在 C 和 C++ 的绝对优势下甚至都无法在性能上望其项背。

如果说 Go 比 C++ 要慢 20%,那么 Go 就要比任何非静态和编译型语言快 2 到 10 倍,并且能够更加高效地使用内存。

其实比较多门语言之间的性能是一种非常猥琐的行为,因为任何一种语言都有其所擅长和薄弱的方面。例如在处理文本方面,那些只处理纯字节的语言显然要比处理 Unicode 这种更为复杂编码的语言要出色的多。有些人可能认为使用两种不同的语言实现同一个目标能够得出正确的结论,但是很多时候测试者可能对一门语言非常了解而对另一门语言只是大概明白,测试者对程序编写的手法在一定程度也会影响结果的公平性,因此测试程序应该分别由各自语言的擅长者来编写,这样才能得到具有可比性的结果。另外,像在统计学方面,人们很难避免人为因素对结果的影响,所以这在严格意义上并不是科学。还要注意的是,测试结果的可比性还要根据测试目标来区别,例如很多发展十多年的语言已经针对各类问题拥有非常成熟的类库,而作为一门新生语言的 Go 语言,并没有足够的时间来推导各类问题的最佳解决方案。如果你想获取更多有关性能的资料,请访问 Computer Language Benchmark Game(详见引用 27)。

这里有一些评测结果:

  • 比较 Go 和 Python 在简单的 web 服务器方面的性能,单位为传输量每秒:

    原生的 Go http 包要比 web.py 快 7 至 8 倍,如果使用 web.go 框架则稍微差点,比 web.py 快 6 至 7 倍。在 Python 中被广泛使用的 tornado 异步服务器和框架在 web 环境下要比 web.py 快很多,Go 大概只比它快 1.2 至 1.5 倍(详见引用 26)。

  • Go 和 Python 在一般开发的平均水平测试中,Go 要比 Python 3 快 25 倍左右,少占用三分之二的内存,但比 Python 大概多写一倍的代码(详见引用 27)。

  • 根据 Robert Hundt(2011 年 6 月,详见引用 28)的文章对 C++、Java、Go 和 Scala,以及 Go 开发团队的反应(详见引用 29),可以得出以下结论:

    • Go 和 Scala 之间具有更多的可比性(都使用更少的代码),而 C++ 和 Java 都使用非常冗长的代码
    • Go 的编译速度要比绝大多数语言都要快,比 Java 和 C++ 快 5 至 6 倍,比 Scala 快 10 倍。
    • Go 的二进制文件体积是最大的(每个可执行文件都包含 runtime)。
    • 在最理想的情况下,Go 能够和 C++ 一样快,比 Scala 快 2 至 3 倍,比 Java 快 5 至 10 倍。
    • Go 在内存管理方面也可以和 C++ 相媲美,几乎只需要 Scala 所使用的一半,比 Java 少 4 倍左右。

与 C 进行交互

工具 cgo 提供了对 FFI(外部函数接口)的支持,能够使用 Go 代码安全地调用 C 语言库,你可以访问 cgo 文档主页:http://golang.org/cmd/cgo。cgo 会替代 Go 编译器来产生可以组合在同一个包中的 Go 和 C 代码。在实际开发中一般使用 cgo 创建单独的 C 代码包。

如果你想要在你的 Go 程序中使用 cgo,则必须在单独的一行使用 import "C" 来导入,一般来说你可能还需要 import "unsafe"

然后,你可以在 import "C" 之前使用注释(单行或多行注释均可)的形式导入 C 语言库(甚至有效的 C 语言代码),它们之间没有空行,例如:

// #include <stdio.h>
// #include <stdlib.h>
import "C"

名称 "C" 并不属于标准库的一部分,这只是 cgo 集成的一个特殊名称用于引用 C 的命名空间。在这个命名空间里所包含的 C 类型都可以被使用,例如 C.uintC.long 等等,还有 libc 中的函数 C.random() 等也可以被调用

当你想要使用某个类型作为 C 中函数的参数时,必须将其转换为 C 中的类型,反之亦然,例如:

var i int
C.uint(i) 		// 从 Go 中的 int 转换为 C 中的无符号 int
int(C.random()) // 从 C 中 random() 函数返回的 long 转换为 Go 中的 int

下面的 2 个 Go 函数 Random()Seed() 分别调用了 C 中的 C.random()C.srandom()

示例 3.2 c1.go

package rand

// #include <stdlib.h>
import "C"

func Random() int {
	return int(C.random())
}

func Seed(i int) {
	C.srandom(C.uint(i))
}

C 当中并没有明确的字符串类型,如果你想要将一个 string 类型的变量从 Go 转换到 C 时,可以使用 C.CString(s);同样,可以使用C.GoString(cs) 从 C 转换到 Go 中的 string 类型。

Go 的内存管理机制无法管理通过 C 代码分配的内存。

开发人员需要通过手动调用 C.free 来释放变量的内存:

defer C.free(unsafe.Pointer(Cvariable))

这一行最好紧跟在使用 C 代码创建某个变量之后,这样就不会忘记释放内存了。下面的代码展示了如何使用 cgo 创建变量、使用并释放其内存:

示例 3.3 c2.go

package print

// #include <stdio.h>
// #include <stdlib.h>
import "C"
import "unsafe"

func Print(s string) {
	cs := C.CString(s)
	defer C.free(unsafe.Pointer(cs))
	C.fputs(cs,(*C.FILE)(C.stdout))
}

构建 cgo 包

Makefile 文件(因为我们使用了一个独立的包),除了使用变量 GOFILES 之外,还需要使用变量 CGOFILES 来列出需要使用 cgo 编译的文件列表。例如,示例 3.2 中的代码就可以使用包含以下内容的 Makefile 文件来编译,你可以使用 gomake 或 make:

include $(GOROOT)/src/Make.inc
TARG=rand
CGOFILES=\
c1.go\
include $(GOROOT)/src/Make.pkg

与 C++ 进行交互

SWIG(简化封装器和接口生成器)支持在 Linux 系统下使用 Go 代码调用 C 或者 C++ 代码。这里有一些使用 SWIG 的注意事项:

  • 编写需要封装的库的 SWIG 接口。
  • SWIG 会产生 C 的存根函数
  • 这些库可以使用 cgo 来调用
  • 相关的 Go 文件也可以被自动生成

这类接口支持方法重载、多重继承以及使用 Go 代码实现 C++ 的抽象类。

目前使用 SWIG 存在的一个问题是它无法支持所有的 C++ 库,比如说它就无法解析 TObject.h。



参考资料:

1) 《The Way to Go》的中文版:https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/directory.md) 

原文链接:https://www.f2er.com/go/188194.html

猜你在找的Go相关文章