Table of Contents

Go

Go is OpenSource

HTTP(S)协议

Go入门指南:https://learnku.com/docs/the-way-to-go
Go语言圣经(中文版):https://yar999.gitbook.io/gopl-zh
Go语言高级编程(Advanced Go Programming):https://chai2010.cn/advanced-go-programming-book/index.html

Python 和 Ruby 程序员:转到 Go 是因为他们并未放弃太多的表达能力,但是获得了性能,并且与并发共舞。
C++ 程序员:无法转到 Go 是因为他们经过艰辛的战斗才获得对其语言的精确控制能力,而且也不想放弃任何已经获得的东西。对于他们,软件不仅仅是关于让工作完成,而是关于用一个确定的方式完成。
Source: 为什么 Go 不被 C++ 程序员喜欢

祖传代码:


基础

go version
// 单文件的使用方式
// hello.go
// 执行:go run hello.go
// 编译:go build hello.go
 
// VS Code 请安装Go的插件,可以自动格式化,挺舒服的
 
// 包(package)的声明
// 「你必须在源文件中非注释的第一行指明这个文件属于哪个包」
// 如何理解包呢?
package main
 
// 引入包
import "fmt"
 
// 声明变量,类型写在后面,没有赋予初值
// 变量需要预先声明,并且区分类型
var x int
 
// 声明常量
// var 换成 const
// 「常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型」
const Pi float64 = 3.14159265358979323846
 
// 常量用作枚举,这里没有显式指明数据类型,交给编译器自行推断
const (
	Unknown = 0
	Female  = 1
	Male    = 2
)
 
// iota是一个特殊常量,借助它可以这样写
// 基本特点是会自增,一个小小语法糖,这里就不详述了
const (
	MESSAGE = iota // 0
	WARNING        // 1
	ERROR          // 2
)
 
// 这是一个可选函数,如果有的话就会被首先执行
func init() { // 注意:"{" 不能写在单独的行上(我开始有点讨厌Go了,代码风格都要管)
	fmt.Println("Init") // 末尾不要分号
}
 
// 程序的入口函数,为了构建一个完整的应用程序必须要有
func main() {
	fmt.Println("Hello, World!")
 
	x = 1 // 普通赋值
	x++   // 支持自增自减
 
	// 运算符:看起来和C差不多
	// + - * / % ++ -- == != < > <= >=
	// && || ! & | ^ << >>(不支持"~"?)
	// += -= &= |=(类似这样的,也都支持)
	// 指针用:& *
 
	// 建议还是使用明确标示长度的数据类型
	// 数据类型转换如下所示
	var y int32 = int32(x) + 1
	// 如果赋予初值,则可以不指定类型(我还是喜欢手动指定)
	var z = y + 1
	// 同时声明多个变量
	// var x1, x2 int32
 
	// var c int // 声明
	// c = 1 // 赋值
	// 相当于
	// var c int = 1
	// 相当于
	// c := 1 // 声明 & 赋值
 
	// 多变量同时赋值
	// v1, v2, v3 := x, y, z
	// 注意,使用冒号进行变量声明、赋值的形式,只能出现在函数体内部
 
	// 同时声明多个不同类型的变量
	// var (
	// 	d1 int32
	// 	d2 bool
	// )
 
	fmt.Println("x = ", x, "and y = ", y, "and z = ", z)
 
	// 数据类型
	// uint<8, 64>, int<16, 64>, float<32, 64>, complex<64, 128>
	// byte(uint8), uintptr, string
 
	// 变量声明周期:和C类似
	// 局部:函数内部声明、函数参数
	// 全局:函数外部声明
 
	var p3 float64 = Pi * 3
 
	// 指针(Go支持指针,这点不错)
	// 初看起来和C也差不多
	// 支持指针,但无指针算术;自动垃圾回收(GC)
	var p *int32 = &y
	fmt.Println("address is", p, "value is", *p)
	p = nil // Go's nullptr
 
	// 分支
	if p3 > 10 {
		fmt.Println("10 ~")
	} else {
		if p3 > 9 {
			fmt.Println("9 ~ 10")
		} else {
			fmt.Println("~ 9")
		}
	}
 
	// 基础使用和C类似,但是不需要手动break
	switch z {
	case 0:
	case 1, 2, 3:
		fallthrough // 强制执行后面的case
	case 100:
	default:
	}
 
	// select
	// 结构上和switch类似,但是需要对Go有更深的理解,不在基础语法部分详述了
 
	// 数组
	// 这里手动指定了数组大小
	// 其实也可以交给编译器自动推断大小(如果有初始化的话)
	nums := [5]int32{127, 988, 1024}
	// var nums [5]int32
	// 访问方式和C一样
	// 以上是基础用法,更多语法糖在数组专题总结
 
	// 循环
	// 类C的写法(不太现代)
	// 可以只写循环条件,类似C的for(;condition;)
	for i := 0; i < 500; i++ {
		if i == 1 {
			continue
		}
		if i == 5 {
			break
		}
		// goto 也可以使用,这里没有举例
		fmt.Print(i, i*i, ",")
	}
	fmt.Println()
 
	// 遍历一个数组,idx = [0, 5)
	for idx, value := range nums {
		fmt.Print(idx, value, ",")
	}
	fmt.Println()
 
}
 
// 定义结构体
type Person struct {
	name string
	id   uint8
	// 不能定义成员函数
}
 
func sayHello(p *Person) {
	// 直接访问一个结构体 or 通过指针访问,都是使用"."操作符
	fmt.Println("Hello, my name is", p.name, "my ID is", p.id)
}
 
// 小写字母开头:只在包的内部可见
// 参数列表可以省略前面的数据类型,写成这样:(x, y int32)
// 「默认情况下,Go 语言使用的是值传递」
// 返回值类型写在后面,可以返回多个返回值
func some_func(x int32, y int32) (int32, bool) {
	// 初始化一个结构体的写法
	var me Person = Person{name: "zh", id: 1}
	sayHello(&me)
 
	return x + y, true
}
 
// 大写字母开头:可以被包外部调用
// 常量、变量等符号,也是一样根据开头的字母大小写区分外部是否可见(这优雅吗?)
func SomeFunc() bool {
	v, b := some_func(1, 2)
	return b && v == 3
}
 
// 函数指针、闭包、方法等高级内容,这里没有介绍
 
// 「Go 语言没有传统面向对象语言中的类(class)和继承(inheritance)概念
// 而是通过组合(composition)和接口(interface)来实现类似的功能」
 
// 其他高级专题:
// 切片(Slice)、范围(Range)、集合(Map)

专题

  1. 面向对象(对于Go来说这种说法可能不太恰当)
  2. 模块与包(Modules & Package)
  3. 自行分发代码(不借助Github)
  4. 并行(多“线程”:go 和 chan)
  5. 测试(test)

开发框架

Go的指令

go version

go run .
go run main.go

go build / go build . # 构建当前目录的Package,依赖会被自动build
(module root) go build ./... # 递归构建整个module

go test / go test . # 测试当前Package,默认不会递归
(module root) go test ./... # 测试整个module

# ./... 表示“从当前目录开始,递归地把所有子目录都包括进来”

go mod init <url>
go get <url>

go mod tidy # 整理 go.mod 和 go.sum,保证它们和你的实际代码一致,修改 go.mod 后就执行一下

ORM

数据库中的ORM

import (
    "gorm.io/driver/sqlite"
    "gorm.io/gorm"
)

杂项

后端框架

Go很适合进行后端开发,可以直接用标准库开发,也可以选择使用框架来提高开发效率、简化结构管理,常用的后端框架(好像都是「单体服务」的框架?不是微服务的框架):

  1. Gin
  2. Fiber
  3. Echo
  4. Beego
  5. GoFrame

微服务

微服务(Microservices)是一种软件架构风格,它将大型应用程序拆分为一组小型、独立的服务模块。每个服务专注于实现特定的业务功能,运行在独立的进程中,并通过轻量级的通信机制(如 HTTP API)进行交互。这种架构使得各个服务可以由不同的团队独立开发、部署和维护,从而提高了系统的灵活性和可扩展性。

Go非常适合微服务:

优势 说明
编译成静态二进制 一行命令构建出无需依赖的可执行文件,易于部署
启动快、内存占用小 适合容器化、服务拆分
并发能力强 goroutine 轻量,处理高并发天然优势
标准库支持好 net/http + JSON + gRPC 支持开箱即用
良好的部署体验 配合Docker、K8s 极其顺畅

微服务模式有多个「节点」,节点之间是需要通信的

因为软件系统太复杂、太庞大,才需要使用微服务的模式,反而是比较简单的系统,一般会使用单体服务

Protobuf

可以作为Go的通信协议使用。都是Google开发的,一起用应该很方便吧…