go语言环境及基本常识2
Easul Lv6

code-server搭建golang环境

  1. 在扩展安装go插件(发布者名称是golang)

  2. 在自己安装软件的目录下载go的二进制包

    折叠代码块BASH 复制代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    cd ~/software
    # 下载go的二进制安装包
    # 下载地址可从这里查找=> https://golang.google.cn/dl/
    wget https://golang.google.cn/dl/go1.17.6.linux-amd64.tar.gz
    # 解压安装包
    tar -zxvf go1.17.6.linux-amd64.tar.gz
    # 在.bashrc中添加go的环境变量配置
    vim ~/.bashrc
    # 在最后一行添加下边的内容并保存。GOROOT根据自己的go解压路径填写
    # GOPATH需要自己先创建好以后放所有go项目的文件夹,然后填写那个文件夹的路径

    GOPATH=/root/work/go-project
    export GOPATH
    GOROOT=/root/software/go
    PATH=$GOROOT/bin:$PATH
    export PATH

    # 刷新.bashrc
    source ~/.bashrc
    # 测试go是否安装成功
    go version
  3. 进入设置界面(CTRL+,),下拉界面,随便找到一个在settings.json中编辑,点击进入,然后在根大括号中添加如下json内容

    折叠代码块JSON 复制代码
    1
    2
    3
    4
    {
    "go.goroot": "/root/software/go",
    "go.gopath": "/root/work/go-project"
    }

    如下为参数解释

    折叠代码块YAML 复制代码
    1
    2
    "go.goroot": 解压的go根目录
    "go.gopath": 自己的go项目目录,以后所有的go工程都放到这个目录下
  4. CTRL + SHIFT + P,调出命令面板,输入Go: Install/Update Tools,用于安装go相关的插件,勾选所有的插件,然后安装即可

常用操作

命令行命令

折叠代码块BASH 复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 更新依赖模块
# 非官方模块在pkg/mod下
# 1. 下载当前项目所需要的依赖模块,并进行模块的相关更新
go get -u
# 2. 优化 go.mod 的依赖文件
go mod tidy
# 项目初始化,声明自己的模块
# 会在go.mod中指定该项目的模块名
# 模块名可以为 github.com/easul/mytest
go mod init myproject
# 项目运行
go run main.go
# 项目编译
go build main.go
# 编译后赋新名字
go build -o othername test.go
# 单元测试
go test test/my_test.go
# 只测试某个测试文件的函数
# -run 指定测试函数
# -v 输出详细日志
go test -run ^TestGetArea$ -v test/my_test.go
# 设置镜像后再安装模块
export GOPROXY=https://goproxy.cn
go get gopkg.in/yaml.v3

单元测试

折叠代码块GOLANG 复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 参考:http://c.biancheng.net/view/5409.html
// 测试用例文件不会参与正常源码的编译,不会被包含到可执行文件中;
// 测试用例的文件名必须以_test.go结尾;
// 需要使用 import 导入 testing 包;
// 测试函数的名称要以Test或Benchmark开头,后面可以跟任意字母组成的字符串,但第一个字母必须大写,例如 TestAbc(),一个测试用例文件中可以包含多个测试函数;
// 单元测试则以(t *testing.T)作为参数,性能测试以(t *testing.B)做为参数;
// 测试用例文件使用go test命令来执行,源码中不需要 main() 函数作为入口,所有以_test.go结尾的源码文件内以Test开头的函数都会自动执行。

import "testing"

func TestGetArea(t *testing.T) {
area := GetArea(40, 50)
if area != 2000 {
t.Error("测试失败")
}
}

测试的时候可以使用如下命令来进行详细结果的输出

折叠代码块BASH 复制代码
1
2
3
# -v 表示输出详细结果
# -run 可以指定运行某个函数
go test -run ^TestGetArea$ -v test/my_test.go

不同平台的编译

折叠代码块BASH 复制代码
1
2
3
4
5
6
7
8
# 不同平台的架构参考
# https://blog.csdn.net/qq_36657175/article/details/124024503
# 编译参考
# https://blog.csdn.net/inthat/article/details/120327137
export CGO_ENABLED=0
export GOOS=linux
export GOARCH=arm
go build hello.go

基础知识

变量

折叠代码块GO 复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package test

// 声明全局变量
var n1 = 100// 普通声明
var (
name, age = "jack", 12// 声明多个
sex = "female"
height = 12
)

func test() {
// 定义局部变量、
// 变量第一种使用方式
// 声明为int型变量。在内存申请int长度的空间
// 声明后不赋值是有默认值的
var number int
// 为变量赋值。在内存中为该空间赋值为10
number = 10

// 变量第二种使用方式
// 如果不声明变量类型,会自动推导数据类型,这个时候需要有初始值
var number_2 = 10

// 变量第三种使用方式
// 省略var,用:=来代替(从而实现了先定义再赋值)
number_3 := 20// 等价于var number_3 = 20

// 多变量声明
var n1, n2, n3 int// 都声明为int类型
var n4, name, n3 = 100, "tome", 12// 在声明的过程中赋值
n5, sex := 12, "female"// 省略var的定义
}
  • 变量的数据值可以在区域内进行同类型变化
  • 同一作用域变量不能重名

常量

折叠代码块GOLANG 复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// iota相当于一个常量组的行标
// 第一行的iota为1
// 如出现第二个常量组,则iota重置为1
// 如果常量未赋值,则默认赋值上一个常量的值
// 如果上一个赋值为iota,则下一个赋值也是iota
const (
PI = 12
FIRST = iota
SECOND
THIRD = "Hello world"
FORTH
FIFTH = iota
)
fmt.Println(PI)
fmt.Println(FIRST)
fmt.Println(SECOND)
fmt.Println(THIRD)
fmt.Println(FORTH)
fmt.Println(FIFTH)

数据类型

折叠代码块YML 复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
基本数据类型:
数值型:
整型:int(32位系统是4字节,64位系统是8字节), int8, int16, int32(rune), int64, uint(32位系统是4字节,64位系统是8字节), uint8, uint16, uint32, uint64, byte(表示多少位)
浮点型: float32, float64
字符型: 没有char,用byte保存单个字符
布尔型: bool
字符串: string(是基本数据类型)
派生(复杂)数据类型:
指针: Pointer
数组: []
结构体: struct(相当于class)
管道: Channel(用于多并发)
函数: func(也是数据类型)
切片: slice(相当于动态数组)
接口: interface
map: 相当于集合
  • rune和int32类似,用于存unicode码,用于存中文字符串
  • byte和uint类似,用于存储单个字节的字符
  • 不写变量类型,默认int, float64
  • 变量类型要在正确范围内尽量用范围小的,节省空间,效率也高
  • float32和float64可能有精读损失,字节大的精度大。推荐用float64
  • 浮点数存储格式:符号位+指数位+尾数位
  • 浮点数特殊表示方法
    折叠代码块GO 复制代码
    1
    2
    3
    4
    5
    6
    7
    var num1 = 1.2
    // 省略了0
    var num2 = .123
    // 科学计数法表示
    var num3 = 5.1234e2
    var num3 = 5.1234e-2
    var num3 = 5.1234E2

流程语句

if

折叠代码块GOLANG 复制代码
1
2
3
4
// 在if判断的时候条件可以多写一个语句
if num := runtime.NumCPU(); num >= 1 {
fmt.Println("可用CPU核数为:", num)
}

for

折叠代码块GOLANG 复制代码
1
2
3
4
5
6
7
8
// 一般格式
for 初始语句;条件表达式;赋值表达式 {
循环体
}
// 无限循环
for {

}

switch

折叠代码块GOLANG 复制代码
1
2
3
4
5
6
7
8
9
10
11
// fallthrough可以强制执行下一个case,即使下一个case是false
// switch可以不跟初始条件
switch {
case true:
fmt.Println("asdf")
fallthrough
case false:
fmt.Println("ffff")
default:
fmt.Println("aaaa")
}

select

这里指出了 select 中的 case 值判断情况。

折叠代码块GOLANG 复制代码
1
2
3
4
5
6
7
8
9
10
11
// 布尔表达式:如果表达式的值为true,则运行对应的case语句 
// 数字字面量:如果表达式的值为数字,则运行对应的case语句
// 字符串字面量:如果表达式的值为字符串,则运行对应的case语句
// 接收表达式:如果表达式的值可以从channel中接收,则运行对应的case语句
// 这个语句中,如果context不取消,则通道<-b.context.Done()就不会返回值,所以不执行该case
select {
case <-b.context.Done():
return false
default:
return true
}

函数

折叠代码块GOLANG 复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// 1. 直接在返回值上定义返回的数据,不需要return结果,且可以在运行的时候直接调用
func search(searchList []string, limit int, searchFunc func(group string) bool) (results []string) {
if limit <= 0 {
limit = len(searchList)
}
// 这里可以直接调用results变量
log.Error(len(results))
for _, member := range searchList {
if len(results) == limit {
break
}
if searchFunc(member) {
results = append(results, member)
}
}
return
}
function MyTest() {
search([]string{"1"}, 1, func(i string) bool { return i == "2" }, t)
}
// 普通的返回,只需要定义返回值类型即可
func (m Members) Append(user *User) (Members, error) {
return append(m, []*User{user}...), nil
}

// 2. 通过传入函数可以分开数据的使用,底层函数传入一部分数据,高层函数传入一部分数据
func search(searchList Members, limit int, searchFunc func(group *User) bool) (results Members) {
if limit <= 0 {
limit = searchList.Count()
}
for _, member := range searchList {
if results.Count() == limit {
break
}
// 将成员数据传入上级调用的函数
if searchFunc(member) {
results = append(results, member)
}
}
return
}
func (m Members) Search(limit int, searchFuncList ...func(user *User) bool) (results Members) {
// group 是底层函数传入的,在这里还可以使用自己的数据 searchFuncList
return search(m, limit, func(group *User) bool {
for _, searchFunc := range searchFuncList {
if !searchFunc(group) {
return false
}
}
return true
})
}

// 3. func和函数名中间的参数
// 如这里的 g ,相当于类的成员
// handle 就相当于挂载到这个成员的方法
func (g *GroupMessageHandler) handle(msg *openwechat.Message) error {
}

main函数

折叠代码块GOLANG 复制代码
1
2
3
4
5
6
7
8
// main函数所在的包必须是main,但外部文件夹可以不叫main
// go语言的每个文件就相当于是一系列函数的组合,文件的上级文件夹才是包名
// 使用文件内的方法就直接用包名.方法即可
package main

func main() {

}

init函数

这个函数相当于是构造函数,一调用包就会执行
包内的每个文件都可以包含一个 init 函数,导入包后,会按照包内的文件名顺序依次执行其 init 函数。

折叠代码块GOLANG 复制代码
1
2
3
4
5
package site

func init() {
fmt.Println(1)
}

结构体

折叠代码块GOLANG 复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 1. 创建的时候需要用指针,因为需要修改结构体的内容
type Client struct {
client *http.Client
}
client := &Client{client: httpClient}

// 2. 直接创建匿名的结构体
// 结构体有字段 BaseRequest ,类型为 *BaseRequest ,然后传入 request 字段实例
content := struct{ BaseRequest *BaseRequest }{BaseRequest: request}

// 3. 创建结构体时第一个字段不写变量名,则可以用结构体名称来直接使用这个字段
type Friend struct{ *User }
// 这里也可以直接用 Friend 的实例来调用 User ,这样获取到的指针就是 *User 了
friend.User

// 4. 使用 结构体指针类型的 切片
// Members 类型是 []*User ,即 结构体指针切片
// []*User{user}... 的含义是 创建了一个 []*User{} 类型的切片,放入了 user 这个元素,并在最后将切片打散
func (m Members) Append(user *User) (results Members) {
return append(m, []*User{user}...)
}

枚举

golang 中并没有枚举的定义,可使用如下方式来进行枚举的模拟操作

折叠代码块GOLANG 复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 将别名看成是枚举的一个入口
type LoginCode string

// 定义多个枚举值
const (
// LoginCodeSuccess 登录成功
LoginCodeSuccess LoginCode = "200"
// LoginCodeScanned 已扫码
LoginCodeScanned LoginCode = "201"
// LoginCodeTimeout 登录超时
LoginCodeTimeout LoginCode = "400"
// LoginCodeWait 等待扫码
LoginCodeWait LoginCode = "408"
)

// 用字符串转成的枚举与定义的枚举比较
result := LoginCode("200") == LoginCodeSuccess

数据类型

折叠代码块GOLANG 复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 1. 获取数据的类型
number := 12
fmt.Println(reflect.TypeOf(number)) // int

// 2. 转换类型,直接用 类型() 来转换
var number1 int32 = 123456789
number2 := int16(number1)
byteArr := []byte("hello world")
str := string(byteArr)
// 断言是否为该类型,没有问题就可以转
newStr, err := testStr.(string)
// 带有指针的转换
// 获取第一个值,判断是否为 *interface{} 类型,是则获取内容
// 然后判断是否是 string 类型,是的话转为该类型
(*result[0].(*interface{})).(string)

// 3. 如果需要判断是否为某种类型,可以使用 类型断言
if _, ok := number.(int); ok {
fmt.Println("It's type int")
} else {
fmt.Println("It's not type int")
}

私有公有

折叠代码块GOLANG 复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 小写或下划线开头,外部不可访问
const (
// 黑色
_DEBUG_COLOR int = 30
// 绿色
_INFO_COLOR int = 32
)
func getCurrentTime() string {
now := time.Now()
year, month, day := now.Date()
hour, minite, second := now.Clock()
dateTime := fmt.Sprintf("%d-%d-%d %d:%d:%d", year, month, day, hour, minite, second)
return dateTime
}
// 大写外部可访问
func Debug(msg string, params ...any) {
printLog(msg, _DEBUG_COLOR, params...)
}

字符串相关

字符串输出

折叠代码块GOLANG 复制代码
1
2
3
4
5
6
7
8
9
10
name, age, sex := "test", 12, "female"
// 用于字符串的组合输出
fmt.Println("name=", name, "sex=", sex, "sex=", sex)

// 用于字符串的格式化输出
// 双引号里放%T,输出变量的类型
fmt.Printf("%T\n", name)

// 查看变量的占用字节大小
fmt.Printf("%d\n", unsafe.Sizeof(number))

输入多行字符

折叠代码块GOLANG 复制代码
1
2
3
4
5
// 输入多行字符串
str := `你是谁
我是你爸爸
`
fmt.Println(str)

printf的区别

折叠代码块GOLANG 复制代码
1
2
3
4
5
6
// 直接打印格式化字符串
fmt.Printf()
// 返回格式化的字符串
fmt.Sprintf(format string, a ...interface{})
// 将格式化的字符串赋值给一个变量
fmt.Fprintf(w io.Writer, format string, a ...interface{})

长字符串拼接

折叠代码块GOLANG 复制代码
1
2
3
4
5
6
7
// 使用字节缓冲来处理
str1 := "asdf"
str2 := "aaaa"
var c bytes.Buffer
c.WriteString(str1)
c.WriteString(str2)
fmt.Println(c.String())

字符串截取

折叠代码块GOLANG 复制代码
1
2
3
4
5
// 先获取某子串出现的位置,再获取切片
str1 := "asd你好,大师傅"
subStrIndex := strings.Index(str1, "你好") // 正向获取子串下标
subStrIndex = strings.LastIndex(str1, "你好") // 反向获取子串下标
fmt.Println(str1[subStrIndex:])

字符串修改

折叠代码块GOLANG 复制代码
1
2
3
4
5
6
7
// 需要将字符串转为字符数组来进行处理
str1 := "asd你好,大师傅"
byteArr := []byte(str1)
for i := 0; i < 3; i++ {
byteArr[i] = ' '
}
fmt.Println(string(byteArr))
 评论
来发评论吧~
Powered By Valine
v1.5.2