Go项目结构
go.mod
go.sum
*.go
go.mod
是相关Go包的集合,是源代码交换和版本控制的单元
其提供了module
, require
、replace
和exclude
四个命令
module hello
go 1.16
replace example.com/greetings => ../greetings
require example.com/greetings v1.1.0
一个典型的go.mod示例
go.sum
是版本控制相关文件,包含了依赖的module的版本及其Hash
*.go
Go的源文件
package hello
import "testing"
func TestHello(t *testing.T) {
want := "Hello, world."
if got := Hello(); got != want {
t.Errorf("Hello() = %q, want %q", got, want)
}
}
一个典型的Go程序代码
创建Go Module的典型过程(一点点shell命令)
创建文件夹
mkdir hello
cd hello
初始化Go Module
go mod init example.com/hello
单元测试
go test
go test -v # More Detail
显示全部依赖的包
go list -m all
添加依赖
go get example.com/example
清理依赖
go mod tidy
语法
注释
支持 C 风格的块注释 /* */ 和 C++ 风格的行注释 //
btw,顶级声明前面的注释都将作为该声明的文档注释
控制结构
if
if condition {
/* Code Here */
return result
}
最简单的if结构
for
// 类似 C 语言中的 for 用法
for init; condition; post { }
// 类似 C 语言中的 while 用法
for condition { }
// 类似 C 语言中的 for(;;) 用法
for { }
三种常用的方式
for key, value := range oldMap {
newMap[key] = value
}
很方便的切片
Switch
func unhex(c byte) byte {
switch {
case '0' <= c && c <= '9':
return c - '0'
case 'a' <= c && c <= 'f':
return c - 'a' + 10
case 'A' <= c && c <= 'F':
return c - 'A' + 10
}
return 0
}
大概是源码里的
switch不会自动向下追溯,所以要使用逗号分隔相同处理的条件,例如:
func shouldEscape(c byte) bool {
switch c {
case ' ', '?', '&', '=', '#', '+', '%':
return true
}
return false
}
结构体、方法与接口
结构体与方法
type Student struct {
name string
age int
}
func (stu *Student) hello(person string) string {
return fmt.Sprintf("hello %s, I am %s", person, stu.name)
}
func main() {
stu := &Student{
name: "Tom",
}
msg := stu.hello("Jack")
fmt.Println(msg) // hello Jack, I am Tom
}
其他零碎内容
单元测试
package greetings
import (
"testing"
"regexp"
)
// TestHelloName calls greetings.Hello with a name, checking
// for a valid return value.
func TestHelloName(t *testing.T) {
name := "Gladys"
want := regexp.MustCompile(`\b`+name+`\b`)
msg, err := Hello("Gladys")
if !want.MatchString(msg) || err != nil {
t.Fatalf(`Hello("Gladys") = %q, %v, want match for %#q, nil`, msg, err, want)
}
}
// TestHelloEmpty calls greetings.Hello with an empty string,
// checking for an error.
func TestHelloEmpty(t *testing.T) {
msg, err := Hello("")
if msg != "" || err == nil {
t.Fatalf(`Hello("") = %q, %v, want "", error`, msg, err)
}
}
一个单元测试的样例 测试文件一定要包含test字样
testing.T与testing.M
testing.T 是普通测试包
testing.M函数可以在测试函数执行之前做一些其他操作
项目结构
- cmd //函数主程序
- internal //私有库
- pkg //公开库
- vendor //依赖
- web //静态Web资源
- configs //配置
- init //系统初始化
- scripts //安装、构建、部署等脚本
- build //打包和持续集成
- deployments IaaS, Paas, 系统, 容器编排的部署配置和模板
- test //额外的外部测试软件和测试数据
- docs //用户及设计文档
- examples //应用或者库的示例文件
- tools //项目的支持工具
- third_party //外部辅助工具, forked 代码, 以及其他第三方工具
- githooks
- assets //资源文件
- website //站点配置数据
错误处理
package greetings
import (
"errors"
"fmt"
)
// Hello returns a greeting for the named person.
func Hello(name string) (string, error) {
// If no name was given, return an error with a message.
if name == "" {
return "", errors.New("empty name")
}
// If a name was received, return a value that embeds the name
// in a greeting message.
message := fmt.Sprintf("Hi, %v. Welcome!", name)
return message, nil
}
并发
协程
在函数或方法前添加 go
关键字能够在新的 Go 协程中调用它。当调用完成后, 该 Go 协程也会安静地退出。(效果有点像 Unix Shell 中的 &
符号,它能让命令在后台运行。)
go list.Sort() // 同时运行 list.Sort ; 不需要等待