GoLang #
gopher是一种生活在加拿大的小动物,go的吉祥物就是这个小动物, 它的中文名叫做囊地鼠,他们最大的特点就是挖洞速度特别快,当然可能不止是挖洞啦。
Go 编程语言是Google公司的一个开源项目,它使程序员更具生产力。Go 语言具有很强的表达能力,它简洁、清晰而高效。得益于其并发机制, 用它编写的程序能够非常有效地利用多核与联网的计算机,其新颖的类型系统则使程序结构变得灵活而模块化。 Go 代码编译成机器码不仅非常迅速,还具有方便的垃圾收集机制和强大的运行时反射机制。 它是一个快速的、静态类型的编译型语言,感觉却像动态类型的解释型语言。(摘取自官网)
Go语言(或 Golang)起源于 2007 年,并在 2009 年正式对外发布。Go 是非常年轻的一门语言,它的主要目标是兼具Python 等动态语言的开发速度和 C/C++ 等编译型语言的性能与安全性。
Go语言是编程语言设计的又一次尝试,是对类C语言的重大改进,它不但能让你访问底层操作系统,还提供了强大的网络编程和并发编程支持。Go语言的用途众多,可以进行网络编程、系统编程、并发编程、分布式编程。
此外,很多重要的开源项目都是使用Go语言开发的,其中包括 Docker、Go-Ethereum、Thrraform 和 Kubernetes。
创始人 #
- Ken Thompson
- 贝尔实验室 Unix 团队成员,C语言、Unix 和 Plan 9 的创始人之一,在 20 世纪 70 年代,设计并实现了最初的 UNIX 操作系统,仅从这一点说,他对计算机科学的贡献怎么强调都不过分。他还与 Rob Pike 合作设计了 UTF-8 编码方案。
- Rob Pike
- Go语言项目总负责人,贝尔实验室 Unix 团队成员,除帮助设计 UTF-8 外,还帮助开发了分布式多用户操作系统 Plan 9、Inferno 操作系统和 Limbo 编程语言,并与人合著了《The Unix Programming Environment》,对 UNIX 的设计理念做了正统的阐述。
- Robert Griesemer
- 就职于 Google,参与开发 Java HotSpot 虚拟机,对语言设计有深入的认识,并负责 Chrome 浏览器和 Node.js 使用的 Google V8 JavaScript引擎的代码生成部分。
思想 #
Less can be more
- 大道至简,小而蕴真
- 让事情变得复杂很容易,让事情变得简单才难
- 深刻的工程文化
核心特性 #
1、并发编程 #
Go语言在并发编程方面比绝大多数语言要简洁不少,这一点是其最大亮点之一,也是其在未来进入高并发高性能场景的重要筹码。
不同于传统的多进程或多线程,golang的并发执行单元是一种称为goroutine的协程。
由于在共享数据场景中会用到锁,再加上GC,其并发性能有时不如异步复用IO模型,因此相对于大多数语言来说,golang的并发编程简单比并发性能更具卖点。
在当今这个多核时代,并发编程的意义不言而喻。当然,很多语言都支持多线程、多进程编程,但遗憾的是,实现和控制起来并不是那么令人感觉轻松和愉悦。Golang不同的是,语言级别支持协程goroutine并发(协程又称微线程,比线程更轻量、开销更小,性能更高),操作起来非常简单,语言级别提供关键字go用于启动协程,并且在同一台机器上可以启动成千上万个协程。协程经常被理解为轻量级线程,一个线程可以包含多个协程,共享堆不共享栈。协程间一般由应用程序显式实现调度,上下文切换无需下到内核层,高效不少。协程间一般不做同步通讯,而golang中实现协程间通讯有两种:1、共享内存型,即使用全局变量加mutex锁来实现数据共享;2、消息传递型,即使用一种独有的channel机制进行异步通讯。
对比Java的多线程和GO的协程实现,明显更直接、简单。这就是GO的魅力所在,以简单、高效的方式解决问题,关键字go,或许就是GO语言最重要的标志。
2、内存回收(GC) #
从C到C++,从程序性能的角度来考虑,这两种语言允许程序员自己管理内存,包括内存的申请和释放等。因为没有垃圾回收机制所以C/C++运行起来速度很快,但是随着而来的是程序员对内存使用上的很谨小慎微的考虑。因为哪怕一点不小心就可能会导致“内存泄露”使得资源浪费或者“野指针”使得程序崩溃等,尽管C++11后来使用了智能指针的概念,但是程序员仍然需要很小心的使用。后来为了提高程序开发的速度以及程序的健壮性,Java和C#等高级语言引入了GC机制,即程序员不需要再考虑内存的回收等,而是由语言特性提供垃圾回收器来回收内存。但是随之而来的可能是程序运行效率的降低。
GC过程是:先stop the world,扫描所有对象判活,把可回收对象在一段bitmap区中标记下来,接着立即start the world,恢复服务,同时起一个专门gorountine回收内存到空闲list中以备复用,不物理释放。物理释放由专门线程定期来执行。
GC瓶颈在于每次都要扫描所有对象来判活,待收集的对象数目越多,速度越慢。一个经验值是扫描10w个对象需要花费1ms,所以尽量使用对象少的方案,比如我们同时考虑链表、map、slice、数组来进行存储,链表和map每个元素都是一个对象,而slice或数组是一个对象,因此slice或数组有利于GC。
GC性能可能随着版本不断更新会不断优化,这块没仔细调研,团队中有HotSpot开发者,应该会借鉴jvm gc的设计思想,比如分代回收、safepoint等。
- 内存自动回收,再也不需要开发人员管理内存
- 开发人员专注业务实现,降低了心智负担
- 只需要new分配内存,不需要释放
3、内存分配 #
初始化阶段直接分配一块大内存区域,大内存被切分成各个大小等级的块,放入不同的空闲list中,对象分配空间时从空闲list中取出大小合适的内存块。内存回收时,会把不用的内存重放回空闲list。空闲内存会按照一定策略合并,以减少碎片。
4、编译 #
编译涉及到两个问题:编译速度和依赖管理
目前Golang具有两种编译器,一种是建立在GCC基础上的Gccgo,另外一种是分别针对64位x64和32位x86计算机的一套编译器(6g和8g)。
依赖管理方面,由于golang绝大多数第三方开源库都在github上,在代码的import中加上对应的github路径就可以使用了,库会默认下载到工程的pkg目录下。
另外,编译时会默认检查代码中所有实体的使用情况,凡是没使用到的package或变量,都会编译不通过。这是golang挺严谨的一面。
5、网络编程 #
由于golang诞生在互联网时代,因此它天生具备了去中心化、分布式等特性,具体表现之一就是提供了丰富便捷的网络编程接口,比如socket用net.Dial(基于tcp/udp,封装了传统的connect、listen、accept等接口)、http用http.Get/Post()、rpc用client.Call(‘class_name.method_name’, args, &reply),等等。
6、函数多返回值 #
在C,C++中,包括其他的一些高级语言是不支持多个函数返回值的。但是这项功能又确实是需要的,所以在C语言中一般通过将返回值定义成一个结构体,或者通过函数的参数引用的形式进行返回。而在Go语言中,作为一种新型的语言,目标定位为强大的语言当然不能放弃对这一需求的满足,所以支持函数多返回值是必须的。
函数定义时可以在入参后面再加(a,b,c),表示将有3个返回值a、b、c。这个特性在很多语言都有,比如python。
这个语法糖特性是有现实意义的,比如我们经常会要求接口返回一个三元组(errno,errmsg,data),在大多数只允许一个返回值的语言中,我们只能将三元组放入一个map或数组中返回,接收方还要写代码来检查返回值中包含了三元组,如果允许多返回值,则直接在函数定义层面上就做了强制,使代码更简洁安全。
7、语言交互性 #
在Go语言中直接重用了大部份的C模块,这里称为Cgo。Cgo允许开发者混合编写C语言代码,然后Cgo工具可以将这些混合的C代码提取并生成对于C功能的调用包装代码。开发者基本上可以完全忽略这个Go语言和C语言的边界是如何跨越的。
golang可以和C程序交互,但不能和C++交互。可以有两种替代方案:1、先将c++编译成动态库,再由go调用一段c代码,c代码通过dlfcn库动态调用动态库(记得export LD_LIBRARY_PATH);2、使用swig。
8、异常处理 #
golang不支持try…catch这样的结构化的异常解决方式,因为觉得会增加代码量,且会被滥用,不管多小的异常都抛出。golang提倡的异常处理方式是:
- 普通异常:被调用方返回
error对象,调用方判断error对象。 - 严重异常:指的是中断性
panic(比如除0),使用defer…recover…panic机制来捕获处理。严重异常一般由golang内部自动抛出,不需要用户主动抛出,避免传统try…catch写得到处都是的情况。当然,用户也可以使用panic(‘xxxx’)主动抛出,只是这样就使这一套机制退化成结构化异常机制了。
9、其他特性 #
-
类型推导:类型定义:支持
var abc = 10这样的语法,让golang看上去有点像动态类型语言,但golang实际上是强类型的,前面的定义会被自动推导出是int类型。作为强类型语言,隐式的类型转换是不被允许的,记住一条原则:让所有的东西都是显式的。简单来说,Go是一门写起来像动态语言,有着动态语言开发效率的静态语言。
-
一个类型只要实现了某个
interface的所有方法,即可实现该interface,无需显式去继承。Go编程规范推荐每个Interface只提供一到两个的方法。这样使得每个接口的目的非常清晰。另外Go的隐式推导也使得我们组织程序架构的时候更加灵活。在写JAVA/C++程序的时候,我们一开始就需要把父类/子类/接口设计好,因为一旦后面有变更,修改起来会非常痛苦。而Go不一样,当你在实现的过程中发现某些方法可以抽象成接口的时候,你直接定义好这个接口就OK了,其他代码不需要做任何修改,编译器的自动推导会帮你做好一切。
-
不能循环引用:即如果
a.go中import了b,则b.go要是import a会报import cycle not allowed。好处是可以避免一些潜在的编程危险,比如a中的func1()调用了b中的func2(),如果func2()也能调用func1(),将会导致无限循环调用下去。 -
defer机制:在Go语言中,提供关键字defer,可以通过该关键字指定需要延迟执行的逻辑体,即在函数体
return前或出现panic时执行。这种机制非常适合善后逻辑处理,比如可以尽早避免可能出现的资源泄漏问题。可以说,defer是继goroutine和channel之后的另一个非常重要、实用的语言特性,对defer的引入,在很大程度上可以简化编程,并且在语言描述上显得更为自然,极大的增强了代码的可读性。
-
“包”的概念:和python一样,把相同功能的代码放到一个目录,称之为包。包可以被其他包引用。main包是用来生成可执行文件,每个程序只有一个main包。包的主要用途是提高代码的可复用性。通过package可以引入其他包。
-
编程规范:GO语言的编程规范强制集成在语言中,比如明确规定花括号摆放位置,强制要求一行一句,不允许导入没有使用的包,不允许定义没有使用的变量,提供gofmt工具强制格式化代码等等。奇怪的是,这些也引起了很多程序员的不满,有人发表GO语言的XX条罪状,里面就不乏对编程规范的指责。要知道,从工程管理的角度,任何一个开发团队都会对特定语言制定特定的编程规范,特别像Google这样的公司,更是如此。GO的设计者们认为,与其将规范写在文档里,还不如强制集成在语言里,这样更直接,更有利用团队协作和工程管理。
-
交叉编译:比如说你可以在运行 Linux 系统的计算机上开发运行 Windows 下运行的应用程序。这是第一门完全支持 UTF-8 的编程语言,这不仅体现在它可以处理使用 UTF-8 编码的字符串,就连它的源码文件格式都是使用的 UTF-8 编码。Go 语言做到了真正的国际化!
适合用来做什么 #
- 云原生应用:Docker、Kubernetes、Etcd等核心工具均用Go编写
- 微服务架构:适合开发高并发、分布式的API服务
- DevOps工具:Prometheus、Grafana等监控工具
- 分布式系统:分布式数据库、消息队列、缓存系统
- 网络编程:代理服务器、负载均衡、网关
安装sdk #
下载 #
Windows #
官网:https://golang.google.cn/
msi可以直接安装到windows系统,全程下一步完事
MacOS #
brew install go
目录结构 #
| 目录名 | 说明 |
|---|---|
| api | 每个版本的 api 变更差异 |
| bin | go 源码包编译出的编译器(go)、文档工具(godoc)、格式化工具(gofmt) |
| doc | 英文版的 Go 文档 |
| lib | 引用的一些库文件 |
| misc | 杂项用途的文件,例如Android平台的编译、git 的提交钩子等 |
| pkg | Windows 平台编译好的中间文件 |
| src | 标准库的源码 |
| test | 测试用例 |
验证安装 #
执行命令:go version
环境变量 #
GOROOT #
GOROOT也就是golang的安装目录根路径,配置到环境变量就好了
如果要使用go命令,需要将%GOROOT%/bin配置到系统环境变量中
GOPATH #
在Go 1.11之前,所有Go代码必须放在GOPATH下。从Go 1.11开始,引入了Go Modules,使项目可以放在任意位置。不过,了解GOPATH仍然很重要。
注意:如果需要在命令行中直接调用GOPATH中install的工具,就需要将$GOPATH/bin配置到环境变量PATH中。
要查看你当前的GOPATH设置,可以运行:go env GOPATH
GOPATH通常包含三个子目录:
src:存放源代码pkg:存放编译后的包文件bin:存放可执行文件
GOPROXY #
proxy 顾名思义就是代理服务器的意思。Go语言在 1.13 版本之后 GOPROXY 默认值为https://proxy.golang.org,由于国内的网络有防火墙的存在,这导致有些Go语言的第三方包我们无法直接通过go get命令获取。GOPROXY 是Go语言官方提供的一种通过中间代理商来为用户提供包下载服务的方式。要使用 GOPROXY 只需要设置环境变量 GOPROXY 即可。
目前公开的代理服务器的地址有:
- goproxy.io
- goproxy.cn(推荐)由国内的七牛云提供。
Windows 下设置 GOPROXY 的命令为:
go env -w GOPROXY=https://goproxy.cn
MacOS 或 Linux 下设置 GOPROXY 的命令为:
export GOPROXY=https://goproxy.cn
测试配置 #
执行命令:go env
Go工程结构 #
GOPATH模式(弃用) #
注意:此项目管理方式为最早的go1.0时所使用,现在不推荐使用,原因是:GOPATH模式下没有版本控制的概念,在执行 go get 的时候,获取的永远是最新的依赖包,下载到GOPATH/src,如果你有两个工程依赖一个包的v1和v2版本,则会发生冲突,因为 GOPATH 模式下两个工程内依赖的导入路径都是一样的,因此两个工程获取的都是v2版本。
前面搭建Go语言开发环境时添加了环境变量 GOPATH,项目的构建主要是靠它来实现的。就是说,如果想要构建一个项目,就需要将这个项目的目录添加到 GOPATH 中,多个项目之间可以使用;分隔。
如果不配置 GOPATH,即使处于同一目录,代码之间也无法通过绝对路径相互调用。
--GOPATH
--src //所有源代码都存放到这个文件
--project1 //目录一般为包名称
--xx.go //源码文件
--main.go //源码文件
--project2
--xx.go //源码文件
--bin
--pkg //自动生成,不需要创建
一个Go语言项目的目录一般包含以下三个子目录:
- src 目录:放置项目和库的源文件;
- 用于以包(package)的形式组织并存放 Go 源文件,这里的包与 src 下的每个子目录是一一对应。例如,若一个源文件被声明属于 log 包,那么它就应当保存在 src/log 目录中。
- 并不是说 src 目录下不能存放 Go 源文件,一般在测试或演示的时候也可以把 Go 源文件直接放在 src 目录下,但是这么做的话就只能声明该源文件属于 main 包了。正常开发中还是建议大家把 Go 源文件放入特定的目录中。
- 包是Go语言管理代码的重要机制,其作用类似于Java中的 package 和 C/C++的头文件。Go 源文件中第一段有效代码必须是
package <包名>的形式,如 package hello。 - 另外需要注意的是,Go语言会把通过
go get命令获取到的库源文件下载到 src 目录下对应的文件夹当中。
- pkg 目录:放置编译后生成的包/库的归档文件;
- 用于存放通过
go install命令安装某个包后的归档文件。归档文件是指那些名称以“.a”结尾的文件。 - 该目录与 GOROOT 目录(也就是Go语言的安装目录)下的 pkg 目录功能类似,区别在于这里的 pkg 目录专门用来存放项目代码的归档文件。
- 编译和安装项目代码的过程一般会以代码包为单位进行,比如 log 包被编译安装后,将生成一个名为 log.a 的归档文件,并存放在当前项目的 pkg 目录下。
- 用于存放通过
- bin 目录:放置编译后生成的可执行文件。
- 与 pkg 目录类似,在通过
go install命令完成安装后,保存由 Go 命令源文件生成的可执行文件。在类 Unix 操作系统下,这个可执行文件的名称与命令源文件的文件名相同。而在 Windows 操作系统下,这个可执行文件的名称则是命令源文件的文件名加 .exe 后缀。
- 与 pkg 目录类似,在通过
社区推荐结构 #
由于现在的go项目不需要再放在GOPATH下了,目前社区最推荐的项目结构为:https://github.com/golang-standards/project-layout,虽然它并不是官方和社区的规范,但因为组织方式比较合理,被很多 Go 开发人员接受。
应用开发目录 #
-
web:前端代码存放目录,主要用来存放
Web静态资源,服务端模板和单页应用(SPAs)。 -
cmd:一个项目中可以会有多个组件(模块),对应的命令源码文件存放在这里。
-
internal:存放私有的库源码文件。你不希望在其他应用和库中被导入,可以将这些代码放在这里,因为在引入其它项目
internal下的包时,Go语言会在编译时报错。 -
pkg:该目录中存放可以被外部应用使用的库源码文件,其他项目可以直接通过
import导入这里的代码。 -
vendor:项目依赖,可通过
go mod vendor创建。需要注意的是,如果是一个Go库,不要提交vendor依赖包。 -
third_party:外部帮助工具,分支代码或其他第三方应用(例如 Swagger UI)。比如我们
fork了一个第三方go包,并做了一些小的改动,我们可以放在目录/third_party/forked下。
应用测试目录 #
- test:用于存放其他外部测试应用和测试数据。
/test目录的构建方式比较灵活:对于大的项目,有一个数据子目录是有意义的。例如,如果需要 Go 忽略该目录中的内容,可以使用/test/data或/test/testdata目录。需要注意的是,Go 也会忽略以.或_开头的目录或文件。这样在命名测试数据目录方面,可以具有更大的灵活性。
应用部署目录 #
- configs:这个目录用来配置文件模板或默认配置。
- deployments:用来存放
Iaas、PaaS系统和容器编排部署配置和模板(Docker-Compose,Kubernetes/Helm,Mesos,Terraform,Bosh)。在一些项目,特别是用Kubernetes部署的项目中,这个目录可能命名为deploy。 - init:存放初始化系统(
systemd,upstart,sysv)和进程管理配置文件(runit,supervisord)。比如sysemd的unit文件。这类文件,在非容器化部署的项目中会用到。
项目管理目录 #
- Makefile:一个 Go 项目在其根目录下应该有一个 Makefile 工具,用来对项目进行命令管理,Makefile 通常用来执行静态代码检查、单元测试、编译等功能。
- scripts:该目录主要用来存放脚本文件,实现构建、安装、分析等不同功能。通常可以考虑包含以下 3 个目录:
/scripts/make-rules:用来存放 makefile 文件,实现 /Makefile 文件中的各个功能。Makefile 有很多功能,为了保持它的简洁,我建议你将各个功能的具体实现放在 /scripts/make-rules 文件夹下/scripts/lib:shell 库,用来存放 shell 脚本。一个大型项目中有很多自动化任务,比如发布、更新文档、生成代码等,所以要写很多 shell 脚本,这些 shell 脚本会有一些通用功能,可以抽象成库,存放在 /scripts/lib 目录下,比如 logging.sh,util.sh 等。/scripts/install:如果项目支持自动化部署,可以将自动化部署脚本放在此目录下。如果部署脚本简单,也可以直接放在 /scripts 目录下。
- build:这里存放安装包和持续集成相关的文件。这个目录下有 3 个大概率会使用到的目录,在设计目录结构时可以考虑进去。
/build/package:存放容器(Docker)、系统(deb,rpm,pkg)的包配置和脚本。/build/ci:存放CI的配置文件和脚本。/build/docker:存放子项目各个组件的Dockerfile文件。
- tools:存放这个项目的支持工具。这些工具可导入来自
/pkg和/internal目录的代码。 - githooks:
Git钩子。比如,我们可以将commit-msg存放在该目录。 - assets:项目使用的其他资源 (图片、
CSS、JavaScript等)。 - website:如果你不使用
Github页面,则在这里放置项目的网站数据。
应用文档目录 #
- README.md:项目的
README文件一般包含了项目的介绍、功能、快速安装和使用指引、详细的文档链接以及开发指引等。 - docs:存放设计文档、开发文档和用户文档等(除了 godoc 生成的文档)。推荐存放以下几个子目录:
/docs/devel/{en-US,zh-CN}:存放开发文档、hack 文档等。/docs/guide/{en-US,zh-CN}: 存放用户手册,安装、quickstart、产品文档等,分为中文文档和英文文档。/docs/images:存放图片文件。
- CONTRIBUTING.md:开源就绪的项目,用来说明如何贡献代码,如何开源协同等等。
CONTRIBUTING.md不仅能够规范协同流程,还能降低第三方开发者贡献代码的难度。 - api:存放的是当前项目对外提供的各种不同类型的 API 接口定义文件,其中可能包含类似
/api/protobuf-spec、/api/thrift-spec、/api/http-spec、openapi、swagger的目录,这些目录包含了当前项目对外提供和依赖的所有 API 文件。 - LICENSE:版权文件可以是私有的,也可以是开源的。常用的开源协议有:
Apache 2.0、MIT、BSD、GPL、Mozilla、LGPL。 - CHANGELOG:当项目有更新时,为了方便了解当前版本的更新内容或者历史更新内容,需要将更新记录存放到
CHANGELOG目录。 - examples:存放应用程序或者公共包的示例代码
建议 #
不要使用src目录:在默认情况下,Go 语言的项目都会被放置到 $GOPATH/src 目录下(GOPATH模式的时候)。这个目录中存放着所有代码,如果我们在自己的项目中使用 /src 目录,这个包的导入路径中就会出现两个 src。
对于小型项目,可以考虑先包含 cmd、pkg、internal 3 个目录,其他目录后面按需创建。
IDE #
Goland #
VsCode #
使用需要安装插件
安装后重启vscode,使用ctrl+shift+p,搜索go:install/update tools,全选进行安装
安装完成后,可以看到bin目录下出现这些可执行工具
HelloWorld #
创建工程 #
mkdir helloworld
cd helloworld
go mod init ygang.top/helloworld
main.go #
//这是一个main包
//这是main包的包注释
package main // 声明 main 包
import (
"fmt" // 导入 fmt 包,打印字符串是需要用到
)
func main() { // 声明 main 主函数
fmt.Println("Hello World!") // 打印 Hello World!
}
package #
Go语言以“包”作为管理单位,每个 Go 源文件必须先声明它所属的包,格式如下:
package name
package 是声明包名的关键字,name 为包的名字
- 一个目录下的同级文件属于同一个包。
- 包名可以与其目录名不同。
- main 包是Go语言程序的入口包,一个Go语言程序必须有且仅有一个 main 包。如果一个程序没有 main 包,那么编译时将会出错,无法生成可执行文件。
import #
在包声明之后,是 import 语句,用于导入程序中所依赖的包,导入的包名使用双引号""包围,如果一个import导入多个包,需要用()包围,并且每个包名占一行,格式如下:
import "name"
import(
"name1"
"name2"
)
注意,导入的包中不能含有代码中没有使用到的包,否则Go编译器会报编译错误,例如 imported and not used: "xxx"
main 函数 #
main 函数,它是Go语言程序的入口函数,也即程序启动后运行的第一个函数。main 函数只能声明在 main 包中,不能声明在其他包中,并且,一个 main 包中也必须有且仅有一个 main 函数。
func 函数名 (参数列表) (返回值列表){
函数体
}
- 函数名:由字母、数字、下画线
_组成,其中,函数名的第一个字母不能为数字,并且,在同一个包内,函数名称不能重名。 - 参数列表:一个参数由参数变量和参数类型组成,例如
func foo(a int, b string)。 - 返回值列表:可以是返回值类型列表,也可以是参数列表那样变量名与类型的组合,函数有返回值时,必须在函数体中使用 return 语句返回。
- 函数体:能够被重复调用的代码片段。
注意:Go语言函数的左大括号{必须和函数名称在同一行,否则会报错。
运行和编译 #
Go语言是编译型的静态语言(和C语言一样),所以在运行Go语言程序之前,先要将其编译成二进制的可执行文件。
可以通过Go语言提供的go build或者go run命令对Go语言程序进行编译:
go build命令可以将Go语言程序代码编译成二进制的可执行文件,但是需要我们手动运行该二进制文件;go run main.go命令则更加方便,它会在编译后直接运行Go语言程序,编译过程中会产生一个临时文件,但不会生成可执行文件,这个特点很适合用来调试程序。
语法 #
行分隔符 #
在 Go 程序中,一行代表一个语句结束。每个语句不需要像 C 家族中的其它语言一样以分号;结尾,因为这些工作都将由 Go 编译器自动完成。
如果你打算将多个语句写在同一行,它们则必须使用;人为区分,但在实际开发中并不鼓励这种做法。
fmt.Println("Hello, World!")
fmt.Println("你好")
注释 #
go 中的注释,主要包括了包注释、命令注释、类型注释、函数注释、变量/常量注释部分。
单行注释是最常见的注释形式,可以在任何地方使用以//开头的单行注释;多行注释也叫块注释,以/*开头,并以 */ 结尾。
// 单行注释
/*
多行
注释
*/
包注释 #
每个程序包(Package)都应该有一个包注释,该注释介绍了整个Package相关的信息,并且通常设定了对Package的期望效果。
// Package path implements utility routines for manipulating slash-separated
// paths.
//
// The path package should only be used for paths separated by forward
// slashes, such as the paths in URLs. This package does not deal with
// Windows paths with drive letters or backslashes; to manipulate
// operating system paths, use the [path/filepath] package.
package path
go doc与godoc #
go doc是Go自带的命令,可以通过go doc packageName查看包的说明
godoc需要额外下载并安装
go get -u golang.org/x/tools/cmd/godoc
go install golang.org/x/tools/cmd/godoc@latest
可以使用godoc -http=:6060查看GO API文档,如果在项目目录中使用,还包含了项目的API文档
标识符 #
标识符用来命名变量、类型等程序实体。一个标识符实际上就是一个或是多个字母(A-Z和a-z)数字(0-9)、下划线_组成的序列,但是首个字符不能是数字,标识符不可以使用关键字或保留字
- Go的标识符支持中文,但是不建议使用中文!
- Go标识符严格区分大小写!
Go 代码中会使用到的 25 个关键字或保留字
| break | default | func | interface | select |
|---|---|---|---|---|
| case | defer | go | map | struct |
| chan | else | goto | package | switch |
| const | fallthrough | if | range | type |
| continue | for | import | return | var |
除了以上关键字,Go 语言还有 36 个预定义标识符
| append | bool | byte | cap | close | complex | complex64 | complex128 | uint16 |
|---|---|---|---|---|---|---|---|---|
| copy | false | float32 | float64 | imag | int | int8 | int16 | uint32 |
| int32 | int64 | iota | len | make | new | nil | panic | uint64 |
| println | real | recover | string | true | uint | uint8 | uintptr |
命名规范 #
包和文件目录命名规范 #
包是代码组织的基本单元。Go语言中的包名称应该是简洁、有意义的,并且应该是小写字母。包名称应该是唯一的,能够清晰地反映出包所提供的功能。
包名统一小写,下划线分隔,不要混合大小写(同一个项目下是不允许存在同名的包(package)的。每个包的导入路径(import path)在整个项目中必须是唯一的)
// 推荐:
package order
package order_server
// 不推荐:
package My_Package
package MyPackage
package Mypackage
文件名称命名规范 #
Go语言中的文件名称应该与包名称保持一致。通常情况下,使用小写字母和单词之间的下划线来命名文件。
// 推荐:
order_service.go
// 不推荐:
OrderService.go
orderservice.go
变量和常量命名规范 #
**局部变量/常量使用小驼峰命名法:**即首个单词小写,后续单词首字母大写。
// 推荐:
var orderPrice string
// 不推荐:
var order_price string
**全局变量/常量使用大驼峰命名法:**即首个单词大写,后续单词首字母大写。
// 推荐:
var MongoClient string
// 不推荐:
var Mongo_Client string
函数和方法命名规范 #
**公有方法使用大驼峰命名法:**函数和方法名同样使用驼峰命名法。
// 推荐:
func OrderSum() int
// 不推荐:
func order_sum() int
**私有方法使用小驼峰命名法:**函数和方法名同样使用驼峰命名法。
// 推荐:
func orderSum() int
// 不推荐:
func order_sum() int
结构体和接口命名规范 #
使用大驼峰命名法: 结构体和接口名同样应该使用驼峰命名法
// 推荐:
// 结构体
type OrderDTO struct {}
// 接口
type OrderInterface interface {}
// 不推荐:
// 结构体
type orderDTO struct {}
// 接口
type orderInterface interface {}
API文档地址 #
中文文档:https://studygolang.com/pkgdoc