Go语言基础

Go语言环境搭建

安装Go

官网下载Go语言的安装包,然后按照要求安装即可。

安装完毕后,需要添加系统环境变量GOROOT,其值为Go的安装目录(安装过程中可以自定义),以及在Path里加上安装目录下的bin目录,然后在cmd中输入go version

然后就是配置IDE,我选择的是vscode。需要安装Go插件;并且安装插件依赖工具:调出命令面板输入go install tools,选择Go: Install/Update Tools

工作空间

Go的工作空间是由GOPATH环境变量指定的,在Go早期版本,GOPATH是必须的,即所有的Go项目代码都要保存在GOPATH指定的目录下。但是后面Go引入了Go Module,使用Go Module管理的项目可以放在GOPATH之外。

工作空间是Go比较特别的地方,它要求所有的项目代码都要放在工作空间中,包括自己写的项目代码以及从外部获取的代码可以存在该空间内。工作空间中存在三个文件夹:

  • src:存放项目源代码
  • pkg:存放编译生成的代码
  • bin:存放编译生成的可执行代码

在Go中,是将每一个项目都当作$GOPATH\src的一个包来看待,工作空间的概念就有点类似于Java中的classpath

classpathJVM用到的一个环境变量,它用来指示JVM如何搜索class

很多教程在配置Java环境时都会在系统变量中加上CLASSPATH环境变量,其中.代表当前目录。详见classpath和jar

Go中,GOPATH的作用就是指示一个工作空间:当Go编译文件时,在工作空间中搜索需要的包。

相关文章:Can someone explain why GOPATH is convenient and how it should be used in general?

Go语言基础

变量

定义变量有多种方式:

  • var <varName> <varType> = <value>
  • var <varName> = <value>
  • varName := value
1
2
3
4
5
6
var var1 string = "go"
var var2 = 10
var3 := true

// 常量就是将var换成const
const const1 = 0
  • _是一个特殊的变量名,任何赋予它的值都会被丢弃。
  • Go对于已声明但未使用的变量会在编译阶段报错

数据类型

1
2
3
4
5
6
int8, int16, int32(rune), int64 // 有符号整数
uint8(byte), uint16, uint32, uint64 // 无符号整数
bool // 布尔类型
float32, float64 // 浮点数
complex64, complex128 // 复数 一半位数作实数,一半位数作虚数
string // 字符串

不同类型之间的变量不允许相互赋值或操作,例如intint32之间的赋值

数据结构

  • array:静态数组(数组长度不可变)

    1
    2
    3
    4
    5
    // var <arrayName> [<size>]<typeName>
    var arr [10]int
    // <arrayName> := [<size>]<typeName>{<initVals>}
    a := [3]int{1, 2, 3}
    b := [...]int{1, 2} // 自动根据元素个数来计算长度
  • slice:动态数组

    1
    2
    3
    4
    5
    6
    // 声明方式和array相比就是少了[]中的长度
    var slice []int
    var s1 := []int{1, 2, 3}

    // 可以通过append来向slice中增加内容
    s1 = append(s1, 3) // [1, 2, 3, 3]
  • map:字典

    1
    2
    3
    4
    5
    // var <mapName> map[<keyType>]<valueType>
    var m map[string]int
    // <mapName> := make(map[<keyType>valueType])
    mp := make(map[string]int)
    m1 := map[string]int{"c":1, "c++":2, "go":3}

控制流

Goif-elseforswitch-case三大结构,唯一需要注意的是Go中条件表达式不需要用括号包裹

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// if-else
i := 1
if i > 0 {
// ...
} else {
// ...
}

// for
for i := 0; i < 10; i ++ {
// ...
}

// switch-case
switch i {
case 1: // ....
case 2: // ...
// ...
default: // ...
}

函数

1
2
3
4
5
6
7
8
/*
func funcName(arg1 type1, arg2 type2, ... ) (ret1 type1, ret2 type2) {
// ...
}
*/
func add(a int, b int) (res int, ok bool) {
// ...
}

fmt

1
2
3
4
5
6
7
8
import "fmt"

fmt.Println() // 打印一行
fmt.Printf("%v", s) // 所有类型的变量都是用v通配符
fmt.Printf("%+v", s) // 输出关于s变量的详细信息
fmt.Printf("%#v", s) // 更加详细
f := 3.1415
fmt.Printf("%.2f", f)

拥有以上知识基本上就可以写一些简单的程序了

Go依赖管理

依赖管理演进

GOPATH

GOPTAH指定工作空间的模式下,所有的项目代码都要存放在$GOPATH/src目录下,包括项目代码依赖的包也是存放在该目录下,就会导致下面的问题:两个项目依赖于两个不同版本的包,但是由于两个版本的包不兼容就导致两个项目会有一个有问题,即 无法实现package的多版本控制

Go Vender

项目目录下增加vendor文件,在每个项目内配置该项目所依赖的包

依赖寻址方式:先venderGOPATH

这个方式也会存在一个问题:一个项目依赖于两个package,这两个package又依赖于不同版本的package,这样还是会导致冲突。

Go Module

实现了终极目标:定义版本规则和管理项目依赖关系

  • 通过go.mod文件管理依赖包版本
  • 通过go get/go mod指令工具管理依赖包

配置文件——go.mod

可以看到依赖由几部分组成:包路径、版本号、以及一些特殊标志

版本号

  • 语义化版本:${MAJOR}.${MINOR}.${PATCH}
  • 基于commit的伪版本:vx.0.0-yyyymmddhhmmss-<12位hash码>

特殊标志

  • indirect:表示的是间接依赖。A->B->CAC就是间接依赖
  • 主版本2+模块会在模块路径后增加/vN后缀
  • +incompatible:对于没有go.mod文件且主版本2+的依赖,表示可能出现不兼容的代码逻辑

依赖图

最终编译的时候会使用C 1.4因为会选择最低兼容版本

Proxy

对于go.mod所用到的依赖应该去哪里下载以及如何下载,常见的有Github等第三方代码托管平台,像之前在配置Go语言开发环境时就需要到Github上下载对应的依赖工具。但是依赖第三方代码托管平台上下载依赖会存在一些问题:

  • 无法保证构建稳定性以及依赖可用性:因为作者随时可以修改删除软件版本甚至是整个软件
  • 增加第三方平台压力

一个解决方案就是引入Proxy:它其实是一个服务站点,用来缓存源站中的软件以及对应的软件版本,不会改变,实现依赖的稳定性和可靠性。

使用GOPROXY配置,指定一个服务站点url列表。例如:GOPROXY="https://proxy1.cn, https://proxy2.cn, direct(源站点)",那么就会依次到指定几个网站中下载依赖。

go get/go mod

使用go get/go mod来管理和安装项目的依赖


Go语言基础
http://example.com/2023/01/13/Go/go-language-learning/
作者
zhc
发布于
2023年1月13日
许可协议