一、go语言介绍
go
全称为 Golang
,是开源的编程语言,它能让构造简单、可靠且高效的软件变得非常容易。
使用过C/C++
里面线程的我们应该都知道,其使用起来非常的麻烦,不仅调用麻烦,如果想要同步数据就还需要各种锁,并且一个线程需要占用数兆内存。
而go
中有专门的goroutine
(轻量级线程实现)解决了这个问题,一个goroutine
仅占数K内存大小,并且其有专门的channel
作为goroutine
之间的数据传输结构,完全没有锁的概念,使用起来更加简单。
也正是由于这个极好的特性,go语言在服务器上使用的较多。
而且最重要的是,它的语法非常简单,接近JavaScript
,并且其生成的可执行文件运行效率接近C++
,不仅跨平台,它还有大量的库可以让我们直接使用。
也正由于这个特性,如果有时我们想要节约开发成本,又想要写一个高效率的程序或脚本,那就可以使用go语言(python语言开发虽然快,但执行效率相比较而言真的很低)。
二、go开发环境配置
首先点击这里,去go语言官网下载go安装包:
然后选择自己合适的版本:
因为我用的windows,所以就下载的windows版本。
下载完成后,一路点击安装即可,然后打开控制台,输入go:
有输出信息则安装成功
前面说了,go语言有很多库可以让我们使用,但由于其默认的库都在外网,所以有时候下载起来会很慢(或者根本下载不了)
这时我们就可以调整一下go的默认配置,设置国内代理,打开控制台输入:
go env -w GOPROXY=https://goproxy.cn,direct
这样我们的go语言开发环境就配置好了。
但如果用记事本码代码,有点过于原始,所以一般我们还是要下载个专业的编辑器,比如vscode
,点击这里跳转。
然后你可以在桌面或任意文件夹中,新建一个go
文件夹,里面新建一个main.go
的文件(当然你也可以任意取其它名字,但.go
后缀不要动)。
然后,在控制台中进入这个文件夹(cd命令,或者直接在该文件夹上面的文件路径中输入cmd
,然后Enter
)
然后输入:code .
这是vscode
的命令,.
代表当前目录,即用vscode
打开当前目录。
打开main.go
文件,这时vscode
就会在软件的右下角提醒你安装所有需要的插件,全部点安装即可。
三、Go语言组织结构
先将下面这段代码复制进main.go
文件中:
package main
import "fmt"
func main() {
fmt.Println("Hello world")
}
这时vscode
大概长下面这样:
这就是一段输出Hello World
字符串的代码而已。
Ctrl+S
保存后,在控制台中进入这个目录,输入 go run main.go
:
是不是非常简单!
现在我们就来理一理上面这些步骤都是在干嘛,有什么作用。
- 首先是代码中第一行的
package main
和C/C++
不同,go语言采用包的概念组织代码(一个包相当于C++
中的一个库,类似于vector
),并且我们的主函数所在的程序必须在main
包里面(这是go语言的规定),这个main.go
文件为我们的主函数main
函数所在的文件,因此需要在最前面申明该文件中的代码为main
包中的
- 然后是第二行代码
import "fmt"
既然有申明包,那肯定就有导入包,该行代码的意思就是导入fmt
包。我们将要使用该包中的东西(fmt
为官方标准库,为format
的缩写,即格式化库,常用于输出输入)
- 第三行代码:
func main()
这也是与C/C++的不同之处,即申明一个函数只需要在函数名前面添加func
关键字即可,而main
是必须要的函数名称,为程序的执行入口,这一点和C/C++相同。
- 第四行代码:
fmt.Println("Hello world")
这就是在调用fmt
这个包中的Println
函数,进行打印字符串,安装好vscode
相关go
的插件后,当你输入fmt.
,就会自动提示其拥有的函数
- 控制台命令:
go run main.go
go
即为前面我们安装好的go
语言安装包中的软件,run
代表运行,main.go
则为要运行的文件
但每次运行都需要用源代码也着实有些麻烦了,可不可以只编译呢?
当然也是可以的!将go run main.go
改为下面这个命令即可
go build main.go
事实上,run
命令也是间接调用了build
命令,然后执行的,即先编译,再执行。
这时你就可以在代码目录中看到编译生成的可执行文件了!
为了更加切身体验,所以下面我们来找找上面提到的软件与包,控制台中输入go env
,会列出go
的各种环境变量:
我们主要需要关注的是上面两个变量值,为两个本地路径。
首先来到GOROOT
变量的路径下,在bin
目录中我们就可以看到两个程序:
go.exe
:即编译运行源代码的程序,上面我们已经用过了gofmt.exe
:格式化代码格式的软件
go与C++不同,它有标准的代码格式,即无论你将代码写成什么样,为源代码运行这个gofmt.exe
程序,就会成为标准格式的代码。
而在vscode
中,只要你按Ctrl+S
进行保存,vscode
就会自动为你调用这个程序,使其成为标准格式的代码,因此这个程序我们无需操心
然后是src
目录中:
就可以看到go的标准库源代码,上面我们使用到的fmt
也在其中。
注意,go共享代码不是像C/C++那样提供静态库或动态库,而是直接提供源代码,一个文件夹就代表go中的一个包,包里面的就是源代码。
然后来到GOPATH
目录:
这个目录里面的东西就是用户自己下载的程序或包,比如bin
目录中:
这里有两个exe
程序,它们是当你第一次使用vscode
打开go代码时,提示你安装的。
gopls.exe
:提供了很多 IDE 才有的功能,例如自动补全、重构、工作空间符号搜索、代码美化和诊断分析任何兼容的编辑器前端staticcheck.exe
:看名字就知道,是静态检测代码的。
这些都不用我们管,然后来到pkg
目录中:
首先是两个文件夹:
- mod:存放我们下载的第三方库
- sumdb:记录使用的第三方库相关信息
四、go语法速览
1.基础
相比于C/C++,go的语法很少。
首先是数据类型,常用的有bool
,int
,float32
,string
,更多类型可以点击这里查看。
有了数据类型,接下来就是声明变量,主要有以下几种方式:
var age int //只声明
var ( //同时声明多个,可以这样简写
name string
name1 string
)
var age1 int = 10 //声明的同时进行初始化赋值
var ( //声明并赋值多个
name2 string = "www.kucoding.com"
name3 string = "yushi-"
)
var age2 = 20 //go可自动推断数据类型,因此可不写int,因为根据20可推断出其为int类型
var ( //声明并赋值多个,可省略类型
name4 = "www.kucoding.com"
name5 = "yushi-"
)
age3 := 30 //在声明的同时赋值,则可以用 := 代替 = ,这样就可以不写var关键字
注意其与C/C++的区别,声明变量需要添加关键字var
,并且类型写在变量名的后面。
虽然看上去也挺多的,但事实上我们使用的最多的应该就是最后一种:age3:=30
,这样一看,是不是就简单多了呢?
同时注意go中每条语句后面不需要添加;
,即使你添加了,gofmt.exe
也会给你删掉(vscode中保存代码时,会自动调用)。
还有就是,如果你复制了上面的代码到自己的程序中,可能就会看见报错:
这也是go的特色,不允许你声明不使用的变量,只要你在最后调用一下 fmt.Println
就不会报错了:
小技巧:对于导入库的操作(如
import “fmt”
),你无需亲手操作,只要你在代码中使用到了fmt
,保存一下源码,就会自动为你添加(同时没有使用到的库,也会自动为你去除)
有变量就有常量,只需要将前面声明变量的关键字var
改为const
即可:
const age int = 10 //由于是常量,不可更改,因此必须在声明的同时进行赋值
const age1 = 20 //而go可自动推断数据类型,因此可以简写
const ( //同时定义多个常量
num1 = 0
num2 = 1
num3 = 2
)
const ( //对于有规律的赋值操作,可以使用iota变量,其默认为0,并且每增加一行,就自动加1,该语句与上面的语句等价
num4 = iota
num5
num6
)
至于运算符,就不多说了,C/C++
中有的,go
基本都有,可以点击这里查看go中的运算符。
然后是判断语句,与C/C++
差不多:
b := 0
if b == 0 {
fmt.Println("b为0")
} else if b == 1 {
fmt.Println("b为1")
} else {
fmt.Println("b为其它值")
}
不同点在于,这里的判断语言,无需添加小括号,而且上面的语句还可以进行简化:
if b := 0; b == 0 {
fmt.Println("b为0")
} else if b == 1 {
fmt.Println("b为1")
} else {
fmt.Println("b为其它值")
}
将需要进行判断的变量写在if
中,这样的好处是不污染变量环境,如这里的b
变量名只在当前的if
语句中有效,后面你可以继续重新声明定义b
变量。
然后是switch
语句,与C/C++
同样类似:
b := 0
switch b {
case 0:
fmt.Println("b为0")
case 1:
fmt.Println("b为1")
case 2:
fmt.Println("b为2")
default:
fmt.Println("b为其它值")
}
不同点在于,switch
后面同样不需要小括号,并且每个case
最后不需要添加break
,其默认只执行该case
语句,如果你想要让它继续执行后面的case
语句,可以添加fallthrough
关键字
switch b := 0; b {
case 0:
fmt.Println("b为0")
fallthrough
case 1:
fmt.Println("b为1")
fallthrough
case 2:
fmt.Println("b为2")
default:
fmt.Println("b为其它值")
}
它同样可以将变量声明定义写在内部。
后面不再赘述,如果看到我有这样的写法,说明它就可以这样用。
当添加了fallthrough
关键字后,它就会执行当前语句后,继续执行后的语句,比如上面就会执行0,1,2这三条语句
除了上面那种我们熟悉的写法,go还提供了另外一种写法:
b := 0
switch {
case b == 0:
fmt.Println("b为0")
case b == 1:
fmt.Println("b为1")
case b == 2:
fmt.Println("b为2")
default:
fmt.Println("b为其它值")
}
不过我感觉这变得更麻烦了……反正这种写法我目前用的不多。
然后来到循环语句:
for i := 0; i < 10; i++ {
fmt.Println(i)
}
基本写法与C/C++差不多,只是没有小括号而已。
但go
中的for
比C/C++
中的更加强大,因为go
中没有while
语句,而是直接使用for
语句进行代替:
i := 0
for i < 10 {
fmt.Println(i)
i++
}
如果想要写死循环,那还可以这样写:
i := 0
for{
fmt.Println(i)
i++
}
此时break
关键字就派上用场了,即跳出当前循环,还有continue
关键字,同样也是可以使用的。
除了这两种基本的写法,它还可以遍历数组:
nums := []string{"www.kucoding.com", "yushi-"}
for index, value := range nums {
fmt.Println(index, value)
}
可以用range
关键字来遍历数组,每次遍历会返回两个值,第一个为下标,第二个为该下标对应的值,上面的运行结果为:
0 www.kucoding.com
1 yushi-
这里说一下go
中数组的写法,前面没提到:
var num []int //声明变长的数组
num = append(num, 10) //通过append函数为其添加值,当内存不够时,会自动扩充
var num1 [3]int //声明指定长度的数组
num1[0] = 20 //直接通过下标进行赋值
num3 := []int{1, 2, 3} //变长数组,初始化并赋值
num4 := [3]int{1, 2, 3} //定长数组初始化并赋值
num5 := [3]int{0: 10, 2: 20} //指定位置初始化赋值
fmt.Println(num)
fmt.Println(num1)
fmt.Println(num3)
fmt.Println(num4)
fmt.Println(num5)
结果为:
[10]
[20 0 0]
[1 2 3]
[1 2 3]