Go语言新手入门浅谈
1、 前言
因为工做中存在与Go语言相关的内容,所以最近花费部分时间对Go语言进行了解,从基础语法开始对Go语言开始学习。Go语言语法简单,类C语法的特性致使学习Go语言学习容易,可以极快上手,然而如果但愿深刻理解Go语言仍需在项目实践中不断锤炼。前端
本篇文章首先浅谈我对Go语言诞生环境、语言特点等内容的了解,而且总结Go语言的基础语法,以做交流。本篇文章从一个新手学习Go语言的角度编写,若文中存在需修正之处,欢迎评论留言指正。java
2、 Go语言行业应用
Go语言是2007年底由Robert Griesemer, Rob Pike, Ken Thompson主持开发,后来还加入了Ian Lance Taylor, Russ Cox等人。Go语言于2009年11月开源,在2012年3月发布了Go 1.0稳定版本。如今Go的开发已是彻底开放的,而且拥有一个活跃的社区[1]。git
Go语言的诞生存在其特殊的氛围背景。2007年,Google的首席软件工程师Rob Pike在等待C++编译的漫长等待过程当中,拉上另外两位大佬,Robert Griesemer和Ken Thompson,指望可以创造出另一门可以拥有接近C的执行性能、接近解析性语言的开发效率以及高效的编译速度的开发语言取代C++。三位大佬将此项目命名为Golang,并将它做为自由时间的实验项目。在大约一年后,Google发现了Go语言的巨大潜力而且全力支持,最终发展到目前的地步。此诞生背景最终决定了Go语言的两大特点:类C特性以及为服务端服务。
github
项目名称 | 项目简介 |
---|---|
Docker | golang头号优秀项目,经过虚拟化技术实现的操做系统与应用的隔离,也称为容器; |
Kubernetes | 由google开发,简称k8s,k8s和docker是当前容器化技术的重要基础设施; |
Etcd | 一种可靠的分布式KV存储系统,有点相似于zookeeper,可用于快速的云配置; |
TiDB | 国内PingCAP团队开发的一个分布式SQL数据库,国内不少互联网公司在使用; |
InfluxDB | 时序型DB,着力于高性能查询与存储时序型数据,经常使用于系统监控与金融领域; |
CockroachDB | 云原生分布式数据库,继NoSQL以后出现的新的概念,称为NewSQL数据库; |
Beego | 国人开发的一款及其轻量级、高可伸缩性和高性能的web应用框架; |
go-kit | Golang相关的微服务框架,这类框架还有go-micro、typhon; |
go-ethereum | 官方开发的以太坊协议实现; |
除了上表中展现的项目以外,国内外各大互联网巨头也逐渐将Go语言做为云上服务的技术栈使用。例如:以今日头条为例,早在2017年,今日头条使用Go语言构建了承载了超过80%流量的后端服务,高峰QPS超过700万,日处理请求量超过3000亿。此外京东的消息推送与分布式存储、知乎的推荐系统、网易云信的调度服务等均开始使用Go语言。
golang
3、 IDE介绍
1. Goland
JetBrains做为一家推出过许多功能强大IDE的公司,迄今为止已推出包括:Java的Intellj IDEA、PHP的PHPStorm、 Python的Pycharm、前端的WebStorm在内的集成开发环境。它旗下推出了一款专门面向Go语言的集成开发环境Goland,功能强大,使用十分便捷。Goland社区的插件丰富,功能齐全,使用过程当中碰到的问题少,开箱即食,对新手十分友好。可在jetbrains官网下载Goland产品,下载页面:https://www.jetbrains.com/go/。与IDEA等存在面向我的用户的免费版本不一样的是,Goland仅有收费版本,使用者在免费试用30天后需购买以获取使用权限。web
2. VSCode
VSCode是目前比较流行的轻量型IDE,集成了众多语言的插件,以支持多种语言的开发,其中包括Go语言插件。本段将介绍如何使用VSCode搭建Go语言的开发环境。docker
- 下载VSCode,下载连接为:https://code.visualstudio.com
- 进入VSCode,安装Golang插件,以下图所示,依据次序点击执行: 选择插件市场->搜索Go插件->认准微软出品->点击安装。
- 在VSCode的Setting中配置User Settings中的GOROOT及GOPATH,其余配置默认便可。如图4所示:
其中:GOROOT是Go的安装路径,GOPATH是编译后二进制的存放目的地和import包时的搜索路径,也是你的工做目录。
- 此时新建HelloWorld.go,编写代码,点击运行后,控制台会返回提示,有工具须要安装,可点击右下角弹出的提示框install All进行一键安装,如图5所示。也可打开命令提示符输入以下命令进行工具安装(本地需安装git):
安装gocode:go get -u -v github.com/nsf/gocode
安装gopkgs:go get -u -v github.com/tpng/gopkgs
安装go-outline:go get -u -v github.com/lukehoban/go-outline
安装godef:go get -u -v github.com/rogpeppe/godef
安装golint:
cd $GOPATH/src/golang.org/x
git clone https://github.com/golang/tools.git
git clone https://github.com/golang/lint.git
go get golang.org/x/lint/golint
数据库
在安装过程当中,因为GFW的缘由,可能会致使部分工具源不可用,此问题可经过从Github使用git clone下载到本地再使用本地安装解决后端
- 安装完毕后重启VSCode,便可完成Go语言插件的安装。
4、 语法介绍
1. Hello World
建立hello.go,而且键入以下代码,运行Hello World:数组
package main import "fmt" func main() { fmt.Println("Hello, World!"); }
在此代码中,包含三块主要信息:package、import、func。其中,一个独立go程序须要至少一个main package。此外,还需经过func main声明主函数入口,经过import引入 标准化输入输出包,以实现Hello Wolrd 字符串的打印。
关于package的使用,细节以下所示:
a. Go程序是由一个或多个package组成,若是独立程序,则须要一个main package
b. 每个package由若干个源文件组成,每一个go源文件均需头部声明自身所属的package。
c. 其中同属于一个package的源文件应当存放于同一个目录之下
d. 在使用其余package的包内容时,能够经过import packagename “[package path]”来实现,代码以下:
package study import packageName "path/to/package"
2. 变量声明
Go语言的变量声明方式很是简单且易于阅读,最常规的方式为经过var关键字声明变量: var variable_name variable_type,关键字、变量名、变量类型之间以空格分隔,实例代码以下所示:
func main() { var a int a = 20 fmt.Println(a) }
值得注意的是,Go语言的规范十分严格,设计人员将编码规范融入Go语言的编译规则中。以此实例为例,若仅仅定义、赋值了变量a而未使用,编译时会报错。
除此以外,变量的声明及初始化赋值还存在其余方式,以下所示:
func main() { var a, b int = 20, 30 var c = "HelloWorld" str := "" fmt.Println(a, b, c, str) }
代码中各变量声明方式含义以下所示:
- 定义int型的两个变量a和b,而且分别赋值为20和30
- 定义新变量c,而且赋予初始值,由编译器编译时自动决定变量c的类型
- str := “” 的做用 等同于 var str = “”,表示定义新变量、初始化赋值,而且由编译器编译时自动决定变量str的类型。值得注意的是:=左边必须是未定义过的变量名,已定义过变量使用:=赋值会在编译时出错
3. 函数与方法
Go语言中的函数
函数是基本的代码块,用于执行不一样的业务任务流程。函数定义时指定函数名称、参数以及返回类型,具体格式以下所示:
func function_name( [parameter list] ) [return_types] { 函数体 }
函数由func关键字开始声明,并依次包含函数名、参数列表、返回值列表。值得注意的是,Go语言中的函数可有无返回值、仅返回一个值和返回多个值三种状况可选。其中,返回多个值的实例代码以下所示:
func swap(x, y int) (int, int) { return y, x } func main() { a, b := 1, 2 a, _ = swap(a, b) fmt.Println(a, b) }
当调用多返回值的函数时,须要有对应数量的变量对象接收函数返回值。若不须要多个返回值中的某几个,可使用Go语言中的空白标识符 _ 占位。
Go语言中的方法
方法也是函数,它带有一个特殊的接收器类型,它是在func关键字和方法名之间编写的。能够在方法内部访问接收器。方法能给用户自定义的类型添加新的行为。它和函数的区别在于方法有一个接收者,给一个函数添加一个接收者,那么它就变成了方法。实例代码以下所示:
type Person struct { age int name string gender string } func (p Person) Growup1() Person { p.age++ return p } func Growup2(p Person) Person { p.age++ return p } func main() { p := Person{name: "张三",age: 25, gender: "男"} p = p.Growup1() fmt.Println(p) }
在此代码中,Groupup1与Groupup2二者实现的功能及效果一致。
4. 结构体
结构体的类型在java、c等语言之中均存在,同时也是十分重要的类型。经过结构体的使用将不一样类型的数据组合造成新的数据类型。Go语言中一样存在结构体的类型。结构体的定义以下代码所示:
type struct_variable_type struct { member definition; member definition; ... member definition; }
当定义告终构体后,便可将结构体应用于变量的声明。普通变量的声明及赋值方法一样适用于结构体变量的声明及初始化,以下列实例所示:
type Person struct { name string age int gender string } func main() { var p Person fmt.Println(p) }
此处应值得注意的是,Go语言经过首字母大小写来控制访问权限,不管是变量、常量、方法仍是自定义类型,首字母大写便可被外部包访问,反之则不行。以此实例为例,此处Person类型可被外部包访问,若类型名为person则不行。
除此以外结构体拥有多种初始化方法,包括:
func main() { p1 := Person{"张三", 25, "男"} p2 := Person{ gender: "女",name: "李四", age: 25} p3 := new(Person) }
代码中各方式含义以下:
- 按照结构体中成员变量定义的顺序依次提供初始化值。
- 经过field:value的方式初始化,此方式无需按照结构体中成员变量定义的顺序提供值,可任意改变顺序。
- 经过new方式初始化结构体,结构体中各成员变量会赋予类型默认的初始值。
结构体的访问
在上述初始化方式以后,p1与p2可经过.点操做符用于访问结构的各个字段,以获取或更改字段的值。P3经过new方式初始化,所得的结果为结构体指针。
// The new built-in function allocates memory. The first argument is a type, // not a value, and the value returned is a pointer to a newly // allocated zero value of that type. func new(Type) *Type
在C语言中此状况须要使用来访问对象并操做成员变量,而在Go语言中无需使用,可直接经过点.操做符访问指针对象以及结构中的各个字段。具体代码以下所示:
func main() { p1 := Person{"张三", 25, "男"} p2 := Person{ gender: "女",name: "李四", age: 25} p3 := new(Person) p3.age = 18 p3.name = "Cristina" }
结构体的比较
结构体是值类型,若是结构体中的成员变量是能够比较的,那结构体是能够比较的。若是结构体中对应的字段均相等,则认为两个结构体变量相等。实例代码以下所示:
func main() { p1 := Person{"张三", 25, "男"} p2 := Person{"张三", 25, "男"} if p1 == p2 { fmt.Println("Person1 and Person2 are equal") } }
运行结果以下:
Person1 and Person2 are equal
5. 循环控制
Go语言中循环过程控制主要经过for实现循环执行操做。和java语言相似,For语句的基本语法结构为:
For init; condition; post {}
其中:初始化语句仅被执行一次,在初始化语句执行以后,循环体执行以前将检查condition的条件,若是condition的值为true则执行循环体,不然结束循环。在一次循环体结束后则执行post语句,在此以后再次检查condition状态,并依据结果决定是否继续循环。
在Go语言中没有while关键字,可是能够经过for语句实现while的效果,while效果的for语句的基本语法结构为:
For condition {}
此外,可使用for语句配合range关键字对slice、map、数组进行遍历,此实例代码以下所示:
func main() { array := [...]int{1,2,3,4,5,6,7,8} for i,v := range array { fmt.Printf("数组中第 %d 个值为 %d \n", (i + 1), v) } }
6. 内建容器
Go语言中,除了数字类型、字符类型等基本类型外,还包括数组、切片、Channel等派生类型。本篇文章中主要记录数组、切片两种数据类型的使用。
数组
与C语言中数组的概念一致,Go语言中数组也是一段固定长度的连续内存区间。数组的声明须要指定元素类型以及元素个数,语法格式以下:var variable_name [SIZE] variable_type
以此格式为标准,可得以下实例:
var arr1 [5]int
此实例中,定义了长度为5的整数型数组,而且为全部元素赋予初始值为0。除此以外,Go语言提供了其余声明并初始化数组的方式,具体如实例所示:
func main() { var arr1 [5]int arr2 := [4]int{1,2,3,4} arr3 := [...]int{1,2,3,4,5,6,7,8} fmt.Println(arr1, arr2, arr3) }
在第二种方式中,指定数组长度并使用 := 而非var关键字声明,此方法要求声明的同时必须赋予初始化的值,而且初始化数组内元素的数量必须等于指定的数组长度。
在第三种方式中,可无需指定数组长度,Go语言会根据元素的个数自动设置数组的大小。但须要注意:“[ ]”中必须使用“…”,若无“…” 获得的结果则不是数组而是切片。
切片
Go语言的数组定义完成后长度不可变,在某些特定场景下数组不太适用。Go语言原生支持一种灵活的内置类型:切片。切片是动态分配大小的连续空间,切片自己能够不储存数据,仅产生对底层数组的一个视图,从而灵活地对切片进行数据处理(相似“动态数组”),并经过此方法对底层数组的数据进行处理。此处视图的概念与数据库中的视图概念相似。
切片的内部结构包含地址、大小与容量。其中:
地址:即此段连续内容空间的起始地址
大小:即切片可取值的范围长度。长度可扩展。
容量:即切片所对应底层数组中,从起始地址开始的可用长度。容量可向后扩展,不可向前扩展。
从数组或切片中生成新的切片
切片默认指向一段连续内存区域,能够是数组和切片自己,在一段连续内存区域生成切片是一种生成新切片的典型方式。格式代码以下:
slice[startindex : endindex]
其中:
- slice表示切片目标对象
- startindex表示切片对象的起始索引
- endindex表示切片对象的结束索引
值得注意的是,此方法生成的切片仅仅是源连续内存区域的视图,自己不存储数据,所以对此方法生成切片的数据的更改会直接反应到内存区域,即:被切片的源切片和数组对应值也会更改。以以下实例代码为例:
func main() { a := []int{1,2,3,4} b := a[0:] b[0] = 10 fmt.Println(a, b) }
运行结果为:
[10 2 3 4] [10 2 3 4]
声明切片以生成新切片
每种类型,包括自定义类型,均可以拥有其切片类型,以表示多个该类型元素的连续集合,此方法声明格式以下:
var slice_name []type_name
其中:
- Slice_name表示切片类型的变量名
- Type_name 表示该切片中对应的元素类型
使用make()函数构造新切片
可使用make()函数动态地建立一个新的切片,该方法格式以下:
make( []type_name, len, cap )
其中:
- Type_name:建立的新切片的元素类型
- Len:为该切片分配多少初始元素
- Cap:提早分配的内存区域大小。Cap的设计主要为了提早分配空间,以防止扩展时可能的再次分配空间而影响性能。
当slice扩展至超过容量边界时,系统会自动扩展容量,容量扩展策略是扩展至当前容量的双倍,如下列实例代码为例:
func testslice() { a := make([]int, 3) fmt.Println(len(a), cap(a)) a = append(a, 3) fmt.Println(len(a), cap(a)) } func main() { testslice() }
运行结果为:
3 3
4 6
映射(map)
map是十分重要的数据结构,用以存储任意类型数据的关联关系。Go语言中,map类型定义格式以下所示:
map[KeyType]ValueType
实例代码以下所示:
func testmap() { m := make(map[string]int) m["id1"] = 10001 fmt.Println(m["id1"]) } func main() { testmap() }
此外,map支持在声明时初始化填充内容,实例代码以下:
m := map[string]int{ "id1":10001, "id2":10002, "id3":10003, }
map的遍历
map的遍历可以使用range关键字完成循环,range关键字可依次返回map中的key与value,同时得到键与值。实例代码以下:
func getall() { m := map[string]int{ "id1":10001, "id2":10002, "id3":10003, } for k,v := range m { fmt.Println("key : " , k, " value : " , v) } } func main() { getall() }
运行结果为:
key : id1 value : 10001
key : id2 value : 10002
key : id3 value : 10003
5、 总结
Go语言语法简单,经过以上基础语法学习后,可使用Go语言实现简易功能,然而Go语言中依然存在许多特性,须要长期练习实践、阅读源码才可深刻理解。此外Go语言中还可利用goroutine、 channel实现高性能并发,在闲暇及项目中多多思考以熟练使用。
参考资料:
[1]. 为何要使用 Go 语言?Go 语言的优点在哪里? - 腾讯云技术社区的回答。点击跳转
[2]. 为何要使用 Go 语言?Go 语言的优点在哪里? - 波罗学的回答。点击跳转