开发环境配置
Go语言运行环境(Windows)
访问 go.dev/ ,点击 Download ,选择对应平台安装包,安装即可。
当然,上面的网站需要魔法,如果无法访问上面的网址,可以改为访问 studygolang.com/dl 下载安装
studygolang.com/dl同样有go语言的图书、开源博客、项目指南、官方文档等资源,可以常去看看
Windows环境下,go安装包安装成功后,会自动将go的bin目录添加到Path下,所以不需要再向Path环境变量中添加go的地址
同时我们需要修改GOPATH变量,GOPATH是保存go代码和第三方依赖包(src)、编译时生成的中间文件(pkg)、编译后生成的可执行文件(bin)的地方。
Go语言运行环境(Linux)
运行下列命令
# 下载Go语言二进制包,dl.gogle.com需要魔法,可以使用镜像
wget https://dl.google.com/go/{tar_version}
# 解压缩到/usr/local目录
sudo tar -C /usr/local -xzf {tar_version}
# 设置环境变量
echo "export PATH=$PATH:/usr/local/go/bin" >> ~/.profile
source ~/.profile
# 验证安装
go version
IDE
选择Goland,去Jetbrains官网,下载安装即可。
在Goland中可以设置项目地址,GOROOT(Go的安装路径)以及一些运行参数(比较重要的是GOPROXY,可以使用镜像资源下载第三方依赖包)
镜像资源
基本语法
这里简单整理 Go 的基础语法,可以速查。 一些不明白的可以查阅Go语言圣经
一、Hello World
Go语言输出Hello World实现如下
package main
import "fmt"
func main() {
fmt.Println("Hello world")
}
Go是一门编译型语言,Go语言的工具链将源代码及其依赖转换成计算机的机器指令(即静态编译)。通过go run 文件名命令可以运行Go 代码。通常我们使用go build 文件名来构建Go代码的二进制文件。
Go语言的代码通过包(package)组织,类似于其他语言的库或模块,package main表示该文件属于main包。main包定义了程序的主体,其中main函数就是程序的入口。
二、变量类型
- 布尔型:
true/false - 整形:
uint(8/16/32/64)/int(8/16/32/64) - 浮点型:
float32/float64/complex64/complex128 - 其他类型: byte(类似 uint8), int/uint(32 或 64 位), uintptr(无符号整型,用于存放指针)
- 字符串:默认为 UTF-8编码
- 派生类型:指针/数组/函数/struct/slice/interface/map
三、变量与常量
Go语言中,变量是强类型的,我们在声明变量时一定要指定变量类型。
定义变量有几种方式
第一种是使用var定义变量,通常来说,Go语言可以依据变量的初始值来推断出变量类型,如下
var hello = "Hello world" // 字符串
var num = 1 // 整形
var isTrue = true // 布尔
我们还可以使用:=运算符,作用类似于上面,如
hello := "Hello world"
num := 1
isTrue := true
如果需要强调类型,可以写作下面的形式
var hello string = "Hello world"
var num int32 = 1
var isTrue bool = true
如果不初始化变量,变量的值是什么
- 字符串默认值为空
- 整型、浮点型默认值为 0
- 布尔型默认值为 false
- 指针、channel、func、接口都为 nil
- 数组默认为 []
- 字典默认为 map[]
如果需要定义常量,需要添加关键字const,如
const constHello = "Hello world"
四、条件
Go中的条件语句主要包括if-else以及switch,因为比较类似于其他语言的形式,直接使用代码说明。
// if-else
func main() {
a := 1
if a >= 0 {
fmt.Println("a is a non-negative number")
} else {
fmt.Println("a is a negative number")
}
b := 10
if b > 0 {
fmt.Println("b is a positive number")
} else if b == 0 {
fmt.Println("b is 0")
} else {
fmt.Println("b is a negative number")
}
// switch, Go种switch不需要加break
c := 10
switch c % 3{
case 0: fmt.Println("c 能被3整除")
case 1: fmt.Println("c 被3除余1")
case 2: fmt.Println("c 被3除余2")
}
// 另一种写法,可以当作一串if-else语句
switch {
case c % 3 == 0: fmt.Println("c 能被3整除")
case c % 3 == 1: fmt.Println("c 被3除余1")
case c % 3 == 2: fmt.Println("c 被3除余2")
}
}
五、循环
Go语言中表示循环的关键字仅有for一种(这正体现了Go的Less is more,当然我们可以利用for实现各种不同形式的循环(本质是一样的)。
for i := 0; i <= 3; i++ {
fmt.Println(i)
}
//类似于while
i = 0
for i <= 3 {
fmt.Println(i)
i++
}
// 死循环
i = 0
for {
fmt.Println(i)
i ++
if i > 3 {
break
}
}
六、一些重要的数据类型
1. 数组
数组定义方式如下
var testArray [3]int
for i := 0; i < 3; i++ {
testArray[i] = i
}
//第二种方式
arrayA := [3]int{1, 2, 3}
arrayB := [...]int{1 , 2, 3}
2Darray := [2][2]int{
{1, 2}
{3, 4}
}
Go 中的数组是固定长度的,一旦创建了就不允许改变,空余位置用 0 填补并且不允许越界。一般来说数组使用不是很方便。
2.slice
固定长度的数组不是很方便,所以我们一般都用切片来操作 slice结构体的底层定义如下
type slice struct {
array unsafe.Pointer // 指向数组的指针
len int // 切片中的元素数量
cap int // array 数组的总容量
}
定义slice,一般使用make进行定义,第一个参数表示类型,第二个表示切片长度,第三个表示容积(可省略)
testSlice := make([]int, 2)
testSlice[0] = 1
testSlice[1] = 0
添加元素,使用append方法(因为我们通常不知道返回的slice是否与原slice的指向同一个引用,通常会将插入元素后的slice重新赋值给原slice)
testSlice = append(testSlice, 3, 4)
获取切片大小,使用len方法
len(testSlice)
拷贝
//1
anoSlice := testSlice
//2
another := make([]int, len(testSlice))
copy(another, testSlice)
第一种方法只是将testSlice的引用传递给了anoSlice anoSlice和testSlice实质上指向的是同一个slice 第二种方法使用copy方法 another和testSlice指向的是不同的slice,只是里面内容一样
实质上,切片底层是数组。当空间不够时,切片会将自身复制到一个更大的数组上去。因为切片扩容操作涉及到拷贝,通常在实际使用中为了减小拷贝的开销,会将切片初始值设定的较大。
选取切片部分(类似于Python的List中的操作,但不支持负数索引)
testSlice[1:]
testSlice[:2]
testSlice[1:3]
3. 字典
字典即由一系列键值对组成
定义与添加键值对
Go语言中的range可以同时遍历字典的键和值,当不需要某一部分时可以用_代替
m := make(map[string]int)
m["Hello"] = 1
m["World"] = 2
m1 := map[string]int{"Hello": 1, "world": 2}
for k, v := range m {
fmt.Println(k, v)
}
for _, num := range m1 {
fmt.Println(v)
}
删除键值对使用delete方法
delete(m, "Hello")
七、函数
1.函数定义
在Go语言中,使用func关键字声明一个函数,函数声明的语法与其他语言略有差异。Go语言中函数也是由函数名、参数列表、返回值组成。
Go语言函数声明的通用格式是func funcName(args) (return_type)。
如
func add(num1 int, num2 int) int {
return num1 + num2
}
需要强调的是,Go语言中的参数传递只有值传递,但是具体传的值,可以分为引用类型(指针/map/slice等)和非引用类型(int/string/struct/array等)。当我们传入的参数是非引用类型时,我们修改的参数值不会反映到原变量上去,如果传入的是引用类型,修改变量的内容会导致原变量发生改变(因为参数与原变量指向同一个引用)
2.函数调用
Go语言中函数的调用也类似于其他语言。
3.错误处理
通常来说,Go函数的错误处理很简单,只需要添加一个类型为Error的返回值即可。
比如
func greeting(name string) (string, error) {
if name == "" {
return name, errors.New("Name is nil")
}
Words := fmt.Sprintf("Hello,%v", name)
return Words, nil
}
- 我们添加了一个返回值类型
error,它用于接收程序运行的错误信息。 - 当name为空时,我们返回错误信息
- 如果允许正常,我们的
error为nil,通常来说,nil也是程序运行正常的标志 - 在调用函数时,只需要用一个变量接收
error,并对其进行判断、处理即可。
八、结构体
面向对象是一个重要的思想,Go语言中可以使用结构体实现面向对象。
我们可以使用struct关键字定义类名、成员变量等。
type O struct{
int
}
type T struct {
a int
b O
}
var i1 T // 值类型
var i2 new(T) // 引用类型
在面向对象中,一个对象不仅要包括成员变量,还需要包括对象的方法。Go语言中通过在函数前添加声明,来将某个函数绑定到某个结构体上。
那么函数的定义将变为
func (structName structType) funcName(args) (return_type)
即在函数名前面添加参数名称和需要绑定的结构体即可。
需要注意的是,我们传入的可以是struct的值,也可以传入struct的指针。struct是非引用类型,当我们需要直接修改struct的成员变量的值,我们需要传入指针。
传入的struct和其对应的方法必须在同一个包内。