50天精通Golang(第1天)

目录

一、思想

二、核心特性

2.1并发编程

2.2内存回收(GC)

2.3内存分配

2.4编译

2.5网络编程

2.6函数多返回值

2.7语言交互性

2.8异常处理

2.9其他一些有趣的特性

二、Go语言的优势

1.效率:快速的编译时间,开发效率和运行效率高。

2.自由高效:组合的思想、无侵入式的接口

​3.强大的标准库

4.部署方便:二进制文件,Copy部署

5.简单的并发

6.稳定性

三、Go项目工程结构

3.1gopath目录

3.2编写第一个程序

3.3第一程序的解释说明

3.3.1package

3.3.2import

3.3.3main

3.4包的说明

四、Go的执行原理以及Go的命令

一、Go的源码文件

1.命令源码文件

2.库源码文件

3.测试源码文件

二、Go的命令

1.go run

2.go build

3.go bulid

4.go get

5.其他命令


一、Go语言的核心特性

  1. Go编程语言是一个开源项目  >  程序员更有生产力。
  2. Go简单、清晰、高效。
  3. 其并发机制 > 程序能够有效的利用多核和联网的计算机,其类型系统让程序结构变得灵活而模块化。
  4. Go代码编译成机器码,迅速,还有垃圾收集机制和运行是的反射机制。
  5. 是一个快速的、静态类型的编译型语言。

一、思想

Less can be more.

大道至简,小而蕴真。

让事情变得复杂很容易,让事情变得简单才难。

二、核心特性

2.1并发编程

golang的并发执行单元是一种称为goroutine的协程。(异于传统的多线程多进程)。

协程(goroutine)又称微线程,比线程更轻量、开销更小、性能更高。

一个线程可以包含多个协程,共享堆不共享栈。协程一般由应用程序显示实现调度,上下文切换无需下到内核层。协程间一般不做同步通讯,而golang中实现协程间通讯由两种:1)共享内存性,即使用全局变量+mutex锁来实现数据共享;2)消息传递性,即使用一种独有的channel机制进行异步通讯。

高并发是Golang语言的最大亮点。

2.2内存回收(GC)

GC的过程:先stop the world ,扫描所有对象判活,把可回收对象在一段bitmap区中标记下来,接着立即start the world,恢复服务,同时起一个专门gorountine回收内存到空闲list中以备复用,不物理释放。物理释放由专门线程定期来执行。

GC的瓶颈在于每次扫描所有对象来判活,待收集的对象数目越多,速度越慢。所以尽量使用对象少的方案,比如我们同时考虑链表、map、slice、数组来进行存储,链表和map每个元素都是一个对象,而slice或数组是一个对象,因此slice或数组有利于GC。

2.3内存分配

初始化阶段直接分配一块大内存区域,大内存被切成各个大小等级的块,放入不同的空闲list中,对象分配空间时从空间list中取出大小合适的内存块。内存回收时,会把不用的内存重放回空闲list。空闲内存会按照一定策略合并,以减少碎片。

2.4编译

编译涉及到两个问题:编译速度和依赖管理

目前Golang具有两种编译器,一种建议在GCC基础上的Gccgo,另外一种是分别针对64位*64位和32位*86位计算机的一套编译器(6g和8g)。

依赖管理方面,由于golang绝大多数第三方开源库都在github上,在代码的import中加上对应的github路径就可以使用,库会默认下载到工程的pkg目录下。

另外,编译时会默认检查代码中所有实体的使用情况,凡是没使用到的package或变量,都会编译不通过。这是golang挺严谨的一面。

2.5网络编程

提供了丰富便捷的网络编程接口,比如socket用net.Dial(基于tcp/udp,封装了传统的connect、listen、accept等接口)、http用http.Get/pot()、rpc用client.Call('class_name.method_name', args, &reply),等等。

2.6函数多返回值

函数定义时可以在入参后面再加(a,b,c),表示将有3个返回值a、b、c。

这样要求是有一定现实意义的,比如我们经常要求接口返回一个三元组(errno,errmsg,data),在大多数只允许一个返回值的语言中,我们只能将三元组放入一个map或数组中返回,接收方还要写代码来检查返回值中包含了三元组,如果允许多返回值,则直接在函数定义层面上就做了强制,使代码更简洁安全。

2.7语言交互性

golang可以C程序交互,但不能和C++交互。可以有两种替代方案:1)先将c++编译成动态库,再由go调用一段c代码,c代码通过dlfcn库动态调用动态库(记得export LD_LIBRARY_PATH);2)使用swig。

2.8异常处理

  • 普通异常:被调用方返回error对象,调用方判断error对象。
  • 严重异常:指的是中断性panic(比如除0),使用defer...recover...panic机制来捕获处理。严重异常一般由golang内部自动抛出,不需要用户主动抛出,避免传统try...catch写得到处都是的情况。当然,用户也可以使用panic('xxxx')主动抛出,只是这样就使这一套机制退化成结构化异常机制了。

2.9其他一些有趣的特性

  • 类型推导:类型定义:支持var abc = 10这样的语法,让golang看上去有点像动态类型语言,但golang实际上时强类型的,前面的定义会被自动推导出是int类型。作为强类型语言,隐式的类型转换是不被允许的,记住一条原则:让所有的东西都是显式的。简单来说,Go是一门写起来像动态语言,有着动态语言开发效率的静态语言。
  • 一个类型只要实现了某个interface的所有方法,即可实现该interface,无需显式去继承。Go编程规范推荐每个Interface只提供一到两个的方法。当在实现的工程中发现某些方法可以抽象成接口的时候,直接定义这个接口,其他代码不需要做任何修改,编译器的自动推导会帮你做好一切。
  • 不能循环引用:即如果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工具强制格式化代码等等。

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

二、Go语言的优势

1.效率:快速的编译时间,开发效率和运行效率高。

开发过程中相较于 Java 和 C++呆滞的编译速度,Go 的快速编译时间是一个主要的效率优势。Go拥有接近C的运行效率和接近PHP的开发效率。

2.自由高效:组合的思想、无侵入式的接口

Go语言可以说是开发效率和运行效率二者的完美融合,天生的并发编程支持。Go语言支持当前所有的编程范式,包括过程式编程、面向对象编程、面向接口编程、函数式编程。

​3.强大的标准库

包括互联网应用、系统编程和网络编程。Go里面的标准库基本上已经是非常稳定,网络层、系统层的库非常实用。Go 语言的 lib 库麻雀虽小五脏俱全。Go 语言的 lib 库中基本上有绝大多数常用的库。

4.部署方便:二进制文件,Copy部署

部署太方便了,所以现在很多人用Go开发运维程序。

5.简单的并发

Go语言的Goroutine和Channel就是并发和异步编程的巨大福音。

  • Go 作为一门语言致力于使事情简单化。它并未引入很多新概念,而是聚焦于打造一门简单的语言,它使用起来异常快速并且简单。其唯一的创新之处是 goroutines 和通道。Goroutines 是 Go 面向线程的轻量级方法,而通道是 goroutines 之间通信的优先方式。

  • 创建 Goroutines 的成本很低,只需几千个字节的额外内存,正由于此,才使得同时运行数百个甚至数千个 goroutines 成为可能。可以借助通道实现 goroutines 之间的通信。Goroutines 以及基于通道的并发性方法使其非常容易使用所有可用的 CPU 内核,并处理并发的 IO。相较于 Python/Java,在一个 goroutine 上运行一个函数需要最小的代码。

6.稳定性

Go拥有强大的编译检查、严格的编码规范和完整的软件生命周期工具,具有很强的稳定性,这是因为Go提供了软件生命周期(开发、测试、部署、维护等等)的各个环节的工具,如go tool、gofmt、go test。

三、Go项目工程结构

3.1gopath目录

gopath目录就是我们存储所编写源代码的目录。该目录下往往要有三个子目录:src,bin,pkg。

  • src---里面每一个子目录,就是一个包。包内是Go的源码文件。
  • pkg---编译后生成的,包的目标文件。
  • bin---生成的可执行文件。

3.2编写第一个程序

1.在HOME/go的目录下,(就是GOPATH目录里),创建一个目录叫src,然后再该目录下创建一个文件夹叫hello,在该目录下创建一个文件叫helloworld.go,并双击打开,输入以下内容:

package main

import "fmt"

func main(){
    fmt.Println("Hello,World!")
}

3.3第一程序的解释说明

3.3.1package

  • 在同一个包下面的文件属于同一个工程文件,不用import包,可以直接使用。
  • 在同一个包下面的所有文件的package名,都是一样的。
  • 在同一个包下面的文件package名都建议设为是该目录名,但也可以不是。

3.3.2import

import "fmt" 告诉 Go 编译器这个程序需要使用 fmt 包的函数,fmt 包实现了格式化 IO(输入/输出)的函数。

3.3.3main

main(),是程序运行的入口。

3.4包的说明

源代码都是存放在GOPATH的src目录下,所以我们使用包来组织我们的项目目录结构。

四、Go的执行原理以及Go的命令

一、Go的源码文件

1.命令源码文件

声明自己属于main代码包、包含无参数声明和结果声明的main函数。

命令源码文件被安装以后,GoPATH如果只有一个工作区,那么相应的可执行文件会被存放当前工作区的bin文件夹下;如果有多个工作区,就会安装到GOBIN指向的目录下。

命令源码文件是Go程序的入口。

同时一个代码包中最好也不要放多个命令源码文件。多个命令源码文件虽然可以单独分开go run运行起来,但是无法通过go build和go install。

2.库源码文件

库源码文件就是不具有命令源码文件上述两个特征的源码文件。存在于某个代码包中的普通的源码文件。

库源码文件被安装后,相应的归档文件(.a文件)会被存放在当前的工作区的pkg的平台相关的目录下。

3.测试源码文件

名称以 _test.go 为后缀的代码文件,并且必须包含 Test 或者 Benchmark 名称前缀的函数:

func TestXXX( t *testing.T) {

}

名称以 Test 为名称前缀的函数,只能接受 *testing.T 的参数,这种测试函数是功能测试函数。

func BenchmarkXXX( b *testing.B) {

}

名称以 Benchmark 为名称前缀的函数,只能接受 *testing.B 的参数,这种测试函数是性能测试函数。

现在答案就很明显了:

命令源码文件是可以单独运行的。可以使用 go run 命令直接运行,也可以通过 go build 或 go install 命令得到相应的可执行文件。所以命令源码文件是可以在机器的任何目录下运行的。

二、Go的命令

1.go run

专门用来运行命令源码文件的命令,注意,这个命令不是用来运行所有 Go 的源码文件的!

go run 命令只能接受一个命令源码文件以及若干个库源码文件(必须同属于 main 包)作为文件参数,且不能接受测试源码文件。它在执行时会检查源码文件的类型。如果参数中有多个或者没有命令源码文件,那么 go run 命令就只会打印错误提示信息并退出,而不会继续执行。

2.go build

go build 命令主要是用于测试编译。在包的编译过程中,若有必要,会同时编译与之相关联的包。

  1. 如果是普通包,当你执行go build命令后,不会产生任何文件。
  2. 如果是main包,当只执行go build命令后,会在当前目录下生成一个可执行文件。如果需要在$GOPATH/bin目录下生成相应的exe文件,需要执行go install 或者使用 go build -o 路径/可执行文件。
  3. 如果某个文件夹下有多个文件,而你只想编译其中某一个文件,可以在 go build 之后加上文件名,例如 go build a.go;go build 命令默认会编译当前目录下的所有go文件。
  4. 你也可以指定编译输出的文件名。比如,我们可以指定go build -o 可执行文件名,默认情况是你的package名(非main包),或者是第一个源文件的文件名(main包)。
  5. go build 会忽略目录下以”_”或者”.”开头的go文件。
  6. 如果你的源代码针对不同的操作系统需要不同的处理,那么你可以根据不同的操作系统后缀来命名文件。

3.go bulid

go install 命令是用来编译并安装代码包或者源码文件的。

go install 命令在内部实际上分成了两步操作:第一步是生成结果文件(可执行文件或者.a包),第二步会把编译好的结果移到$GOPATH/pkg或者​$GOPATH/bin

可执行文件: 一般是 go install 带main函数的go文件产生的,有函数入口,所有可以直接运行。

.a应用包: 一般是 go install 不包含main函数的go文件产生的,没有函数入口,只能被调用。

go install 用于编译并安装指定的代码包及它们的依赖包。当指定的代码包的依赖包还没有被编译和安装时,该命令会先去处理依赖包。与 go build 命令一样,传给 go install 命令的代码包参数应该以导入路径的形式提供。并且,go build 命令的绝大多数标记也都可以用于 实际上,go install 命令只比 go build 命令多做了一件事,即:安装编译后的结果文件到指定目录。

安装代码包会在当前工作区的 pkg 的平台相关目录下生成归档文件(即 .a 文件)。 安装命令源码文件会在当前工作区的 bin 目录(如果 GOPATH 下有多个工作区,就会放在 GOBIN 目录下)生成可执行文件。

同样,go install 命令如果后面不追加任何参数,它会把当前目录作为代码包并安装。这和 go build 命令是完全一样的。

go install 命令后面如果跟了代码包导入路径作为参数,那么该代码包及其依赖都会被安装。

go install 命令后面如果跟了命令源码文件以及相关库源码文件作为参数的话,只有这些文件会被编译并安装。

4.go get

go get 命令用于从远程代码仓库(比如 Github )上下载并安装代码包。注意,go get 命令会把当前的代码包下载到 $GOPATH 中的第一个工作区的 src 目录中,并安装。

使用 go get 下载第三方包的时候,依旧会下载到 $GOPATH 的第一个工作空间,而非 vendor 目录。当前工作链中并没有真正意义上的包依赖管理,不过好在有不少第三方工具可选。

如果在 go get 下载过程中加入-d 标记,那么下载操作只会执行下载动作,而不执行安装动作。比如有些非常特殊的代码包在安装过程中需要有特殊的处理,所以我们需要先下载下来,所以就会用到-d 标记。

还有一个很有用的标记是-u标记,加上它可以利用网络来更新已有的代码包及其依赖包。如果已经下载过一个代码包,但是这个代码包又有更新了,那么这时候可以直接用-u标记来更新本地的对应的代码包。如果不加这个-u标记,执行 go get 一个已有的代码包,会发现命令什么都不执行。只有加了-u标记,命令会去执行 git pull 命令拉取最新的代码包的最新版本,下载并安装。

命令 go get 还有一个很值得称道的功能——智能下载。在使用它检出或更新代码包之后,它会寻找与本地已安装 Go 语言的版本号相对应的标签(tag)或分支(branch)。比如,本机安装 Go 语言的版本是1.x,那么 go get 命令会在该代码包的远程仓库中寻找名为 “go1” 的标签或者分支。如果找到指定的标签或者分支,则将本地代码包的版本切换到此标签或者分支。如果没有找到指定的标签或者分支,则将本地代码包的版本切换到主干的最新版本。

5.其他命令

go clean

go clean 命令是用来移除当前源码包里面编译生成的文件,这些文件包括

  • _obj/ 旧的object目录,由Makefiles遗留
  • _test/ 旧的test目录,由Makefiles遗留
  • _testmain.go 旧的gotest文件,由Makefiles遗留
  • test.out 旧的test记录,由Makefiles遗留
  • build.out 旧的test记录,由Makefiles遗留
  • *.[568ao] object文件,由Makefiles遗留
  • DIR(.exe) 由 go build 产生
  • DIR.test(.exe) 由 go test -c 产生
  • MAINFILE(.exe) 由 go build MAINFILE.go产生

go fmt

go fmt 命令主要是用来帮你格式化所写好的代码文件。

比如我们写了一个格式很糟糕的 test.go 文件,我们只需要使用 fmt go test.go 命令,就可以让go帮我们格式化我们的代码文件。但是我们一般很少使用这个命令,因为我们的开发工具一般都带有保存时自动格式化功能,这个功能底层其实就是调用了 go fmt 命令而已。

使用go fmt命令,更多时候是用gofmt,而且需要参数-w,否则格式化结果不会写入文件。gofmt -w src,可以格式化整个项目。

go test

go test 命令,会自动读取源码目录下面名为*_test.go的文件,生成并运行测试用的可执行文件。默认的情况下,不需要任何的参数,它会自动把你源码包下面所有test文件测试完毕,当然你也可以带上参数,详情请参考go help testflag

go doc

go doc 命令其实就是一个很强大的文档工具。

如何查看相应package的文档呢? 例如builtin包,那么执行go doc builtin;如果是http包,那么执行go doc net/http;查看某一个包里面的函数,那么执行go doc fmt Printf;也可以查看相应的代码,执行go doc -src fmt Printf;

# 查看net/http包
localhost:hello ruby$ go doc net/http
# 查看time包
localhost:hello ruby$ go doc time
# 查看某个包里的指定函数
localhost:hello ruby$ go doc fmt Printf

通过命令在命令行执行 go doc -http=:端口号,比如godoc -http=:8080。然后在浏览器中打开127.0.0.1:8080,你将会看到一个golang.org的本地copy版本,通过它你可以查询pkg文档等其它内容。如果你设置了GOPATH,在pkg分类下,不但会列出标准包的文档,还会列出你本地GOPATH中所有项目的相关文档,这对于经常被限制访问的用户来说是一个不错的选择。

localhost:hello ruby$ godoc -http=:9527

go fix 用来修复以前老版本的代码到新版本,例如go1之前老版本的代码转化到go1

go version 查看go当前的版本

go env 查看当前go的环境变量

go list 列出当前全部安装的package

  • 20
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值