go:Go语言介绍、Go开发环境搭建、创建Go项目、变量命名规范、变量的定义和使用
一、Go语言介绍
介绍
Go 即Golang,是Google公司2009年11月正式对外公开的一门编程语言。
Go是【静态强类}型语言,是区别于解析型语言的编译型语言(静态:类型固定 强类型:不同类型不允许直接运算)。
解析型语言——源代码是先翻译为中间代码,然后由解析器对代码进行解释执行。
编译型语言——源代码编译生成机器语言,然后由机器直接执行机器码即可执行。
c,java,c++,c#,go等编译型语言可以把代码编译成可执行文件,这样在操作系统上不需要装任何东西,就可以运行
ps:python是动态强类型语言,不过可以用pipinstaller 把项目编译成可执行文件
拓展:
java有编译过程---》没有编译成机器语言---》字节码文件,机器识别不了---》java虚拟机:jvm能识别
运行java必须要有jvm
jvm:java虚拟机
jre:java运行时环境
jdk:java开发环境
特性
跨平台的编译型语言
语法接近C语言
管道(channel),切片(slice),并发(routine)
有垃圾回收的机制
支持面向对象和面向过程的编程模式
发展历史
2009年11月7日 weekly.2009-11-06 —— 早期的版本
2012年3月28日 go1 —— 稳定版版的发布
2013年5月14日 go1.1 —— 语言本身的变化、库的变化等。
2013年12月01日 go1.2 —— 提供更好的调度和一个新的语言特性。
2014年6月18日 go1.3 —— 主要是在实现的工作上的变化,以及精准的垃圾回收。
2014年12月10日 go1.4 —— 包含了2个很小的语言变更。
2015年8月19日 go1.5 —— 实现的架构变化,同时保留了和旧版本的兼容性,本次更新中移除了”最后残余的C代码”。(语言的自举)
2016年2月7日 go1.6 —— 语言本身、运行时、和库的实现的变化。
2016年8月15日 go1.7 —— 标准库有显着的性能改进和变化。
2017年2月26日 go1.8 —— 标准库有显着的性能改进和变化。
2017年8月24日 go1.9 —— 是包含语言,标准库,以及运行时的诸多变化。这个版本中的大部分工作都是对运行时和工具的改进。
2018年2月16日 go1.10 —— 大部分更改都在工具链,运行时和库的实现中。
2018年8月24日 go1.11 —— modules和WebAssembly支持。(go mod模式 包管理)
2019 年 2 月 go 1.12 —— modules和WebAssembly支持。
2019 年 2 月 go 1.12— — 基于 analysi包重写了 go vet`命令,为开发者写自己的检查器提供了更大的灵活性
2019 年 9 月 go 1.13— — 改进了 sync
包中的 Pool
,在 gc 运行时不会清除 pool。它引进了一个缓存来清理两次 gc 运行时都没有被引用的 pool 中的实例。重写了逃逸分析,减少了 Go 程序中堆上的内存申请的空间
2020 年 2 月 go 1.14— — 现在 Go Module 已经可以用于生产环境,鼓励所有用户迁移到 Module。该版本支持嵌入具有重叠方法集的接口。性能方面做了较大的改进,包括:进一步提升 defer 性能、页分配器更高效,同时 timer 也更高效。现在,Goroutine 支持异步抢占
Go语言应用
谁在用
这个不用多做介绍,作为开发Go语言的公司,当仁不让。Google基于Go有很多优秀的项目,比如:https://github.com/kubernetes/kubernetes ,大家也可以在Github上 https://github.com/google/ 查看更多Google的Go开源项目。
Facebook也在用,为此他们还专门在Github上建立了一个开源组织facebookgo,大家可以通过https://github.com/facebookgo访问查看facebook开源的项目,比如著名的是平滑升级的grace。
腾讯
腾讯作为国内的大公司,还是敢于尝试的,尤其是Docker容器化这一块,他们在15年已经做了docker万台规模的实践,具体可以参考http://www.infoq.com/cn/articles/tencent-millions-scale-docker-application-practice 。
主要职责是:
负责腾讯游戏蓝鲸平台后台开发工作
负责容器相关的开发工作
和蓝鲸平台,容器开发有关。腾讯作为主要使用C/C++的公司,使用Go会方便很多,也有很多优势,不过日积月累的C/C++代码很难改造,也不敢动,所以新业务会在Go方面尝试。
百度
目前所知的百度的使用是在运维这边,是百度运维的一个BFE项目,负责前端流量的接入。他们的负责人在2016年有分享,大家可以看下这个 http://www.infoq.com/cn/presentations/application-of-golang-in-baidu-frontend .
其次就是百度的消息系统,从其最近的Golang招聘介绍就可以看出来.
负责公司手百消息通讯系统服务器端开发及维护
京东
京东云消息推送系统、云存储,以及京东商城等都有使用Go做开发。
小米
小米对Golang的支持,莫过于运维监控系统的开源,也就是 http://open-falcon.com/ 。
此外,小米互娱、小米商城、小米视频、小米生态链等团队都在使用Golang。
360
360对Golang的使用也不少,一个是开源的日志搜索系统Poseidon,托管在Github上,https://github.com/Qihoo360/poseidon.
还有360的推送团队也在使用,他们还写了篇博文在Golang的官方博客上 https://blog.golang.org/qihoo。
360直播在招聘Golang开发工程师。
美团、滴滴、新浪以及七牛等。一般的选择,都是选择用于自己公司合适的产品系统来做,比如消息推送的、监控的、容器的等,Golang特别适合做网络并发的服务,这是他的强项,所以也是被优先用于这些项目。
应用领域
服务开发、并发、分布式、微服务等方向
Go语言项目
docker:基于lxc的一个虚拟打包工具,能够实现PAAS平台的组建。
kubernetes :Kubernetes是Google开源的一个容器编排引擎,它支持自动化部署、大规模可伸缩、应用容器化管理。在生产环境中部署一个应用程序时,通常要部署该应用的多个实例以便对应用请求进行负载均衡
区块链:BTCD 是用go语言实现的完整节点的比特币实现
nsq:bitly开源的消息队列系统,性能非常高,目前他们每天处理数十亿条的消息
packer:用来生成不同平台的镜像文件,例如VM、vbox、AWS等,作者是vagrant的作者
skynet:分布式调度框架
Doozer:分布式同步工具,类似ZooKeeper
Heka:mazila开源的日志处理系统
cbfs:couchbase开源的分布式文件系统
tsuru:开源的PAAS平台,和SAE实现的功能一模一样
groupcache:memcahe作者写的用于Google下载系统的缓存系统
god:类似redis的缓存系统,但是支持分布式和扩展性
gor:网络流量抓包和重放工具
Go语架构
GOPATH的工作区包含bin,src,和pkg这三个:
src——源码(包含第三方的和自己项目的)
bin——编译生成的可执行程序
pkg——编译时生成的对象文件
go适合做什么
- 服务端开发
- 分布式系统,微服务
- 网络编程
- 区块链开发
- 内存KV数据库,例如boltDB、levelDB
- 云平台
Go语言发展前景
Go语言将登上语言榜前列,与C和Java并列前三甲
Go语言称霸云计算
Go将统治下一个10年
目前Go语言已经⼴泛应用于人工智能、云计算开发、容器虚拟化、⼤数据开发、数据分析及科学计算、运维开发、爬虫开发、游戏开发等领域。
Go语言简单易学,天生支持并发,完美契合当下高并发的互联网生态
二、Go开发环境搭建
SDK下载与安装
SDK下载
GO官网:https://go.dev/
安装包下载地址:https://go.dev/dl/
这里的安装包也叫Go的SDK,他相当于Go的开发环境
它包含了Go语言的编译器、标准库、工具链等组件,可以用于开发和运行Go语言程序。Go语言官方发行版支持Windows、macOS、Linux等主流操作系统,并提供了对多种CPU架构的支持。
各个系统对应的包名:
操作系统 | 包名 |
---|---|
Windows | go1.13.3.windows-amd64.msi |
Linux | go1.13.3.linux-amd64.tar.gz |
Mac | go1.13.3.darwin-amd64.pkg |
FreeBSD | go1.13.3.freebsd-amd64.tar.gz |
验证安装是否成功。在命令行中输入go version
命令,如果输出当前安装的Go语言版本号,则说明安装成功。
SDK安装
windows系统
Windows 下可以使用 .msi 后缀(在下载列表中可以找到该文件,如go1.13.3.windows-amd64.msi)的安装包来安装。
默认情况下 .msi 文件会安装在 c:\Go 目录下。将 c:\Go\bin 目录添加到 Path 环境变量中。添加后你需要重启命令窗口才能生效(默认已经添加了,这样在cmd窗口下敲 go 能找到该命令)
MAC系统
Mac下直接双击go1.13.3.darwin-amd64.pkg,一路下一步安装即可
LINUX系统
1、下载二进制包:go1.13.3.linux-amd64.tar.gz
2、将下载的二进制包解压至 /usr/local目录。
tar -C /usr/local -xzf go1.13.3.linux-amd64.tar.gz
3、将 /usr/local/go/bin 目录添加至PATH环境变量:
//这样在任意 位置敲 go 就可以执行
export PATH=$PATH:/usr/local/go/bin
编辑器(IDE)
GO语言常用的编辑器:
- Visual Studio Code:Visual Studio Code是一款轻量级的代码编辑器,支持多种编程语言,包括Go语言。它提供了丰富的插件和扩展,可以方便地进行代码调试、格式化、自动补全等操作。
- GoLand:GoLand是一款专门针对Go语言开发的集成开发环境(IDE),由JetBrains开发。它提供了丰富的代码编辑、调试、版本控制、测试等功能,可以提高开发效率。
ps:vs code没有GoLand那样的右键运行
三、创建Go项目
创建项目
步骤一
点击创建项目按钮
步骤二
选择SDK以及项目创建路径,然后点击创建
步骤三
修改一些编辑器的配置,让他用起来更顺手
调整行距以及文本大小
允许使用鼠标滚轮+ctrl调整字体大小
将terminal从Powershell改成cmd(Powershell有时候会出错)
步骤四
在go文件中编写代码
package main // 声明这个go文件属于哪个包,main有特殊含义,一个项目要运行必须要有main包,运行的入口是main包下的main函数
// 表示导入fmt包,自动导入的,goland自动导入的,使用了哪个包,编辑器会自动导入
// 包导入,不使用,会报错,编译不过
import "fmt"
// func 定义一个函数 ,main 是函数名,没有参数,没有返回值,整个项目入口
func main() {
// 在控制台输出helloworld
fmt.Println("helloworld") // a... 提示的,意思是传的helloworld实参,给了a
}
// 编译代码---》编译成可执行文件---》默认编译成当前平台可执行文件---》支持跨平台编译---》想编译出linux的---》交叉编译
// 编译代码---》编译成可执行文件---》默认编译成当前平台可执行文件---》支持跨平台编译---》想编译出linux的---》交叉编译
//编译 go build 文件名----》编译成可执行文件
// 运行,直接运行 双击
// 开发阶段----》编译并运行---》生成可执行文件,不再当前路径,用完就删除
// 编辑器有个快捷运行方式,右键运行
总结:
我们在开发的时候可以直接跟pycharm一样,右键运行或是点击上方的运行按钮运行代码,也可以用 go build 文件名 的形式创建出可执行文件,再执行带代码
四、变量命名规范
变量定义规范
Go语言中的函数名、变量名、常量名、类型名、语句标号和包名等所有的命名,都遵循一个简单的命名规则:
1 一个名字必须以一个字母(Unicode字母)或下划线开头,后面可以跟任意数量的字母、数字或下划线
2 大写字母和小写字母是不同的:Name和name是两个不同的变量
3 关键字和保留字都不建议用作变量名
25个关键字
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语言中有37个保留字,主要对应内建的常量、类型和函数
内建常量: true false iota nil
内建类型: int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
float32 float64 complex128 complex64
bool byte rune string error
内建函数: make len cap new append copy close delete
complex real imag
panic recover
总结
1、建议定义变量,函数名使用:用驼峰
2、go文件命令:建议用下划线
对比:
python 都用下划线
java 都是驼峰
注意事项拓展
- 这些保留字并不是关键字,可以在定义中重新使用它们。在一些特殊的场景中重新定义它们也是有意义的,但是也要注意避免过度而引起语义混乱
- 如果一个名字是在函数内部定义,那么它就只在函数内部有效。如果是在函数外部定义,那么将在当前包的所有文件中都可以访问。名字的开头字母的大小写决定了名字在包外的可见性。如果一个名字是大写字母开头的(必须是在函数外部定义的包级名字;包级函数名本身也是包级名字),那么它将是导出的,也就是说可以被外部的包访问,例如fmt包的Printf函数就是导出的,可以在fmt包外部访问。包本身的名字一般总是用小写字母
- 名字的长度没有逻辑限制,但是Go语言的风格是尽量使用短小的名字,对于局部变量尤其是这样;你会经常看到i之类的短名字,而不是冗长的theLoopIndex命名。通常来说,如果一个名字的作用域比较大,生命周期也比较长,那么用长的名字将会更有意义
- 在习惯上,Go语言程序员推荐使用 驼峰式 命名,当名字由几个单词组成时优先使用大小写分隔,而不是优先用下划线分隔。因此,在标准库有QuoteRuneToASCII和parseRequestLine这样的函数命名,但是一般不会用quote_rune_to_ASCII和parse_request_line这样的命名。而像ASCII和HTML这样的缩略词则避免使用大小写混合的写法,它们可能被称为htmlEscape、HTMLEscape或escapeHTML,但不会是escapeHtml
- go文件的名字,建议用下划线的方式命名(参见go源码)
五、变量的定义和使用
变量是什么
变量指定了某存储单元(Memory Location)的名称,该存储单元会存储特定类型的值。在 Go 中,有多种语法用于声明变量。
声明单个变量
var name type 是声明单个变量的语法。
package main
import "fmt"
func main() {
var age int // 变量声明
fmt.Println("my age is", age)
}
语句 var age int
声明了一个 int 类型的变量,名字为 age。我们还没有给该变量赋值。如果变量未被赋值,Go 会自动地将其初始化,赋值该变量类型的零值(Zero Value)。本例中 age 就被赋值为 0。如果你运行该程序,你会看到如下输出:
my age is 0
变量可以赋值为本类型的任何值。上一程序中的 age 可以赋值为任何整型值(Integer Value)。
package main
import "fmt"
func main() {
var age int // 变量声明
fmt.Println("my age is", age)
age = 29 // 赋值
fmt.Println("my age is", age)
age = 54 // 赋值
fmt.Println("my new age is", age)
}
上面的程序会有如下输出:
my age is 0
my age is 29
my new age is 54
声明变量并初始化
声明变量的同时可以给定初始值。 var name type = initialvalue 的语法用于声明变量并初始化。
package main
import "fmt"
func main() {
var age int = 29 // 声明变量并初始化
fmt.Println("my age is", age)
}
在上面的程序中,age 是具有初始值 29 的 int 类型变量。如果你运行上面的程序,你可以看见下面的输出,证实 age 已经被初始化为 29。
my age is 29
类型推断(Type Inference)
如果变量有初始值,那么 Go 能够自动推断具有初始值的变量的类型。因此,如果变量有初始值,就可以在变量声明中省略 type
。
如果变量声明的语法是 var name = initialvalue,Go 能够根据初始值自动推断变量的类型。
在下面的例子中,你可以看到在第 6 行,我们省略了变量 age
的 int
类型,Go 依然推断出了它是 int 类型。
package main
import "fmt"
func main() {
var age = 29 // 可以推断类型
fmt.Println("my age is", age)
}
声明多个变量
Go 能够通过一条语句声明多个变量。
声明多个变量的语法是 var name1, name2 type = initialvalue1, initialvalue2。
package main
import "fmt"
func main() {
var width, height int = 100, 50 // 声明多个变量
fmt.Println("width is", width, "height is", heigh)
}
上述程序将在标准输出打印 width is 100 height is 50
。
你可能已经想到,如果 width 和 height 省略了初始化,它们的初始值将赋值为 0。
package main
import "fmt"
func main() {
var width, height int
fmt.Println("width is", width, "height is", height)
width = 100
height = 50
fmt.Println("new width is", width, "new height is ", height)
}
上面的程序将会打印:l
width is 0 height is 0
new width is 100 new height is 50
在有些情况下,我们可能会想要在一个语句中声明不同类型的变量。其语法如下:
var (
name1 = initialvalue1,
name2 = initialvalue2
)
使用上述语法,下面的程序声明不同类型的变量。
package main
import "fmt"
func main() {
var (
name = "naveen"
age = 29
height int
)
fmt.Println("my name is", name, ", age is", age, "and height is", height)
}
这里我们声明了 string 类型的 name、int 类型的 age 和 height(我们将会在下一教程中讨论 golang 所支持的变量类型)。运行上面的程序会产生输出 my name is naveen , age is 29 and height is 0
。
简短声明
Go 也支持一种声明变量的简洁形式,称为简短声明(Short Hand Declaration),该声明使用了 := 操作符。
声明变量的简短语法是 name := initialvalue。
package main
import "fmt"
func main() {
name, age := "naveen", 29 // 简短声明
fmt.Println("my name is", name, "age is", age)
}
运行上面的程序,可以看到输出为 my name is naveen age is 29
。
简短声明要求 := 操作符左边的所有变量都有初始值。下面程序将会抛出错误 cannot assign 1 values to 2 variables
,这是因为 age 没有被赋值。
package main
import "fmt"
func main() {
name, age := "naveen" //error
fmt.Println("my name is", name, "age is", age)
}
简短声明的语法要求 := 操作符的左边至少有一个变量是尚未声明的。考虑下面的程序:
package main
import "fmt"
func main() {
a, b := 20, 30 // 声明变量a和b
fmt.Println("a is", a, "b is", b)
b, c := 40, 50 // b已经声明,但c尚未声明
fmt.Println("b is", b, "c is", c)
b, c = 80, 90 // 给已经声明的变量b和c赋新值
fmt.Println("changed b is", b, "c is", c)
}
在上面程序中的第 8 行,由于 b 已经被声明,而 c 尚未声明,因此运行成功并且输出:
a is 20 b is 30
b is 40 c is 50
changed b is 80 c is 90
但是如果我们运行下面的程序:
package main
import "fmt"
func main() {
a, b := 20, 30 // 声明a和b
fmt.Println("a is", a, "b is", b)
a, b := 40, 50 // 错误,没有尚未声明的变量
}
上面运行后会抛出 no new variables on left side of :=
的错误,这是因为 a 和 b 的变量已经声明过了,:= 的左边并没有尚未声明的变量。
变量也可以在运行时进行赋值。考虑下面的程序:
package main
import (
"fmt"
"math"
)
func main() {
a, b := 145.8, 543.8
c := math.Min(a, b)
fmt.Println("minimum value is ", c)
}
在上面的程序中,c 的值是运行过程中计算得到的,即 a 和 b 的最小值。上述程序会打印:
minimum value is 145.8
由于 Go 是强类型(Strongly Typed)语言,因此不允许某一类型的变量赋值为其他类型的值。下面的程序会抛出错误 cannot use "naveen" (type string) as type int in assignment
,这是因为 age 本来声明为 int 类型,而我们却尝试给它赋字符串类型的值。
package main
func main() {
age := 29 // age是int类型
age = "naveen" // 错误,尝试赋值一个字符串给int类型变量
}
操作代码
package main
import "fmt"
// 变量定义
func main() {
//1 完整定义
// var关键字 变量名 变量类型 = 变量值
//var name string = "lqz"
//fmt.Println(name)
//
//var age int = 19
//fmt.Println(age)
// 2 变量定义了,必须使用,否则报错
// 3 类型推导(不写类型)---》自动推导出lqz 是字符串类型
//var name = "lqz"
//name = "pyy"
//name = 19
//fmt.Println(name)
// 4 虽然是类型推导出来的,但是是有类型的,并且后期不能变换类型
// 变量只要定义了,类型就固定了。后期不能改变
//5 简略声明 ,省略var 省略类型,必须使用 :=
//name:= "lqz"
//fmt.Println(name)
// 6 一次性声明多个变量(其实就是基于上面三种变量定义方式的变形)
// 6.1 完整定义
//var name, age, hobby string = "lqz", "19", "篮球"
//var (
// name string = "lqz"
// age int = 19
// hobby string = "篮球"
//)
//fmt.Println(name)
//fmt.Println(age)
//fmt.Println(hobby)
// 6.2 类型推导
//var name, age, hobby = "lqz", 19, "篮球"
//var(
// name="lqz"
// age=19
// hobby="篮球"
//)
//fmt.Println(name)
//fmt.Println(age)
//fmt.Println(hobby)
// 6.3 简略声明
//name, age, hobby := "lqz", 19, "篮球"
//fmt.Println(name)
//fmt.Println(age)
//fmt.Println(hobby)
// 6.4 6.1和6.2混合
//var(
// name="lqz"
// age int=19
// hobby="篮球"
//)
//fmt.Println(name)
//fmt.Println(age)
//fmt.Println(hobby)
// 7 变量不能重复定义三种定义方式)
//var name = "lqz"
////var name string="pyy"
////name:="pyy"
//name, age := "pyy", 19
//fmt.Println(name)
//fmt.Println(age)
// 8 变量可以先定义在赋值,必须使用完整定义(方式一)
//var name string //默认值 空字符串
//var age int // 默认值是0
//var age 不行
//name := 不行
//age = 19
//fmt.Println(name)
//fmt.Println(age)
// 9 简略声明用的多 a:=10
// 10 查看变量类型
//a := 99
a := "lqz"
fmt.Printf("a的值是:%v,类型是:%T", a, a)
}