Java开发已经是红海一片,面临着35岁危机的压力,需要适时的调整策略,以应对可能会出现的不确定性。毕竟,命运掌握在自己手里,比掌握在公司手里 安全感会强很多。
尝试的其中一条路即为:Java转Go,海外开发web3相关,也有其他的尝试,会开辟相应的专栏收录。
针对每一个部分,都会在最后准备练习题
,可以多做几遍,用于巩固知识,多动手!
后续golang语言学习过程中产生的全部内容,会发布在 web3这个专栏中。
本章会有比较多的练习题,也可以让AI去生成更多的练习,多练习哦!
Go语言基础快速突破[工程管理](1-2周)
1. Go 命令行工具
Go 提供了丰富的命令行工具来帮助开发者进行项目管理和开发:
bash
# 常用Go命令
go version # 查看Go版本
go env # 查看Go环境变量
go mod init # 初始化模块
go mod tidy # 整理依赖
go build # 编译程序
go run # 运行程序
go test # 运行测试
go fmt # 格式化代码
go vet # 代码静态检查
go get # 下载依赖包
go install # 安装程序
实用示例:
bash
# 创建新项目
mkdir myproject && cd myproject
go mod init github.com/username/myproject
# 添加依赖
go get github.com/gin-gonic/gin
# 运行项目
go run main.go
2. 代码风格
2.1 强制性编码规范
Go语言有一些强制性的编码规范,编译器会强制执行:
- 包名规范:包名必须小写,不能包含下划线
- 导出规则:首字母大写的标识符会被导出(public),小写的不会导出(private)
- 格式化 :使用
go fmt
强制统一代码格式 - 未使用的变量/包:编译器会报错
go
// 正确的包声明
package main
import (
"fmt" // 标准库包
"net/http" // 标准库包
)
// 导出的函数(首字母大写)
func PublicFunction() {
fmt.Println("这是公开函数")
}
// 私有函数(首字母小写)
func privateFunction() {
fmt.Println("这是私有函数")
}
2.2 非强制性编码风格建议
遵循Go社区的最佳实践:
- 变量命名:使用驼峰命名法(camelCase)
- 常量命名:全大写或驼峰命名法
- 接口命名:通常以 -er 结尾
- 错误处理:及时处理错误,不要忽略
go
// 推荐的命名风格
var userName string
const MaxRetries = 3
const defaultTimeout = 30
// 接口命名示例
type Reader interface {
Read([]byte) (int, error)
}
type Writer interface {
Write([]byte) (int, error)
}
3. 远程 import 支持
Go支持直接从远程仓库导入包,这是Go的一大特色:
go
import (
"github.com/gin-gonic/gin" // GitHub
"golang.org/x/crypto/bcrypt" // Go官方扩展包
"gopkg.in/yaml.v2" // gopkg.in服务
)
Go Modules 管理依赖:
bash
# go.mod 文件示例
module github.com/username/myproject
go 1.21
require (
github.com/gin-gonic/gin v1.9.1
golang.org/x/crypto v0.14.0
)
4. 工程组织
4.1 GOPATH(已过时)
在Go 1.11之前使用GOPATH模式:
- 所有Go代码必须在GOPATH目录下
- 包路径基于GOPATH/src
- 现在已被Go Modules替代
4.2 目录结构
现代Go项目推荐的目录结构:
bash
myproject/
├── go.mod # 模块定义文件
├── go.sum # 依赖校验文件
├── main.go # 主程序入口
├── README.md # 项目说明
├── cmd/ # 应用程序目录
│ └── server/
│ └── main.go
├── internal/ # 私有代码
│ ├── handler/
│ ├── service/
│ └── model/
├── pkg/ # 可被外部使用的库代码
├── api/ # API定义文件
├── web/ # Web资源
├── configs/ # 配置文件
├── scripts/ # 脚本文件
├── test/ # 额外的测试数据
└── docs/ # 文档
5. 文档管理
Go内置了强大的文档生成工具:
bash
# 生成并查看文档
go doc fmt.Println # 查看特定函数文档
go doc -all fmt # 查看包的所有文档
godoc -http=:6060 # 启动本地文档服务器
编写文档注释:
go
// Package calculator 提供基本的数学计算功能
package calculator
// Add 计算两个整数的和
// 参数 a, b 是要相加的两个整数
// 返回值是两个整数的和
func Add(a, b int) int {
return a + b
}
6. 工程构建
Go提供了简单而强大的构建系统:
bash
# 基本构建
go build # 构建当前目录
go build main.go # 构建指定文件
go build -o myapp # 指定输出文件名
# 构建参数
go build -ldflags "-X main.version=1.0.0" # 设置变量
go build -tags production # 构建标签
# 优化构建
go build -ldflags "-s -w" # 减小二进制文件大小
构建配置示例:
go
//go:build production
// +build production
package config
const Debug = false
7. 跨平台开发
7.1 交叉编译
Go天然支持交叉编译,无需额外配置:
bash
# 查看支持的平台
go tool dist list
# 交叉编译示例
GOOS=linux GOARCH=amd64 go build -o myapp-linux
GOOS=windows GOARCH=amd64 go build -o myapp.exe
GOOS=darwin GOARCH=amd64 go build -o myapp-mac
# 常用平台组合
GOOS=linux GOARCH=arm64 go build # Linux ARM64
GOOS=windows GOARCH=386 go build # Windows 32位
GOOS=darwin GOARCH=arm64 go build # MacOS M1
7.2 Android 支持
Go可以编译为Android应用:
bash
# 安装gomobile
go install golang.org/x/mobile/cmd/gomobile@latest
gomobile init
# 构建Android应用
gomobile build -target android .
gomobile bind -target android github.com/username/mypackage
8. 单元测试
Go内置了测试框架,测试文件以_test.go
结尾:
go
// calculator_test.go
package calculator
import "testing"
func TestAdd(t *testing.T) {
result := Add(2, 3)
expected := 5
if result != expected {
t.Errorf("Add(2, 3) = %d; expected %d", result, expected)
}
}
// 表格驱动测试
func TestAddTable(t *testing.T) {
tests := []struct {
a, b int
expected int
}{
{1, 2, 3},
{0, 0, 0},
{-1, 1, 0},
}
for _, test := range tests {
result := Add(test.a, test.b)
if result != test.expected {
t.Errorf("Add(%d, %d) = %d; expected %d",
test.a, test.b, result, test.expected)
}
}
}
// 基准测试
func BenchmarkAdd(b *testing.B) {
for i := 0; i < b.N; i++ {
Add(1, 2)
}
}
测试命令:
bash
go test # 运行当前包的测试
go test ./... # 运行所有包的测试
go test -v # 详细输出
go test -bench=. # 运行基准测试
go test -cover # 测试覆盖率
go test -race # 竞态检测
9. 打包分发
Go程序可以编译成单一的可执行文件,便于分发:
bash
# 基本打包
go build -o myapp
# 静态链接(适用于容器部署)
CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o myapp
# 使用Docker多阶段构建
Dockerfile示例:
dockerfile
# 构建阶段
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o main .
# 运行阶段
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/main .
CMD ["./main"]
发布策略:
- GitHub Releases:自动化发布多平台二进制文件
- Docker Hub:容器化部署
- 包管理器:如apt、yum等系统包管理器
- Go模块:发布为可导入的Go包
测试题1:Go命令行工具的使用
go
// Package commands 演示Go命令行工具的使用
// 练习1:Go命令行工具实践
package main
import (
"fmt"
"os"
"os/exec"
"strings"
)
// 练习任务:
// 1. 使用go命令创建一个新的模块
// 2. 添加依赖包
// 3. 运行go fmt格式化代码
// 4. 使用go vet检查代码
// 5. 构建可执行文件
// CommandRunner 封装Go命令执行
type CommandRunner struct {
workDir string
}
// NewCommandRunner 创建命令运行器
func NewCommandRunner(workDir string) *CommandRunner {
return &CommandRunner{workDir: workDir}
}
// RunGoCommand 执行Go命令
// TODO: 实现这个函数,执行指定的go命令并返回输出
func (cr *CommandRunner) RunGoCommand(args ...string) (string, error) {
// 提示:使用exec.Command("go", args...)
// 设置工作目录为cr.workDir
// 返回命令输出和错误
// 你的代码在这里
return "", fmt.Errorf("未实现")
}
// InitModule 初始化Go模块
// TODO: 实现模块初始化功能
func (cr *CommandRunner) InitModule(moduleName string) error {
// 提示:调用 go mod init <moduleName>
// 你的代码在这里
return fmt.Errorf("未实现")
}
// AddDependency 添加依赖
// TODO: 实现添加依赖功能
func (cr *CommandRunner) AddDependency(packageName string) error {
// 提示:调用 go get <packageName>
// 你的代码在这里
return fmt.Errorf("未实现")
}
// FormatCode 格式化代码
// TODO: 实现代码格式化功能
func (cr *CommandRunner) FormatCode() error {
// 提示:调用 go fmt ./...
// 你的代码在这里
return fmt.Errorf("未实现")
}
// VetCode 检查代码
// TODO: 实现代码检查功能
func (cr *CommandRunner) VetCode() error {
// 提示:调用 go vet ./...
// 你的代码在这里
return fmt.Errorf("未实现")
}
// BuildProject 构建项目
// TODO: 实现项目构建功能
func (cr *CommandRunner) BuildProject(outputName string) error {
// 提示:调用 go build -o <outputName>
// 你的代码在这里
return fmt.Errorf("未实现")
}
// GetGoVersion 获取Go版本
// TODO: 实现获取Go版本功能
func (cr *CommandRunner) GetGoVersion() (string, error) {
// 提示:调用 go version
// 你的代码在这里
return "", fmt.Errorf("未实现")
}
// ListEnvironment 列出Go环境变量
// TODO: 实现列出环境变量功能
func (cr *CommandRunner) ListEnvironment() (map[string]string, error) {
// 提示:调用 go env,解析输出为键值对
// 你的代码在这里
return nil, fmt.Errorf("未实现")
}
// 辅助函数:解析go env输出
func parseGoEnv(output string) map[string]string {
env := make(map[string]string)
lines := strings.Split(strings.TrimSpace(output), "\n")
for _, line := range lines {
if strings.Contains(line, "=") {
parts := strings.SplitN(line, "=", 2)
if len(parts) == 2 {
key := parts[0]
value := strings.Trim(parts[1], `"`)
env[key] = value
}
}
}
return env
}
// 示例main函数
func main() {
fmt.Println("=== Go命令行工具练习 ===")
// 创建临时目录进行练习
tempDir := "./temp_practice"
os.MkdirAll(tempDir, 0755)
defer os.RemoveAll(tempDir) // 清理临时目录
runner := NewCommandRunner(tempDir)
// 练习1: 获取Go版本
fmt.Println("\n1. 获取Go版本:")
if version, err := runner.GetGoVersion(); err != nil {
fmt.Printf("错误: %v\n", err)
} else {
fmt.Printf("Go版本: %s\n", version)
}
// 练习2: 初始化模块
fmt.Println("\n2. 初始化模块:")
if err := runner.InitModule("practice-module"); err != nil {
fmt.Printf("错误: %v\n", err)
} else {
fmt.Println("模块初始化成功")
}
// 练习3: 添加依赖
fmt.Println("\n3. 添加依赖:")
if err := runner.AddDependency("github.com/stretchr/testify/assert"); err != nil {
fmt.Printf("错误: %v\n", err)
} else {
fmt.Println("依赖添加成功")
}
// 练习4: 列出环境变量
fmt.Println("\n4. Go环境变量:")
if env, err := runner.ListEnvironment(); err != nil {
fmt.Printf("错误: %v\n", err)
} else {
for key, value := range env {
if strings.Contains(key, "GOPATH") || strings.Contains(key, "GOROOT") || strings.Contains(key, "GOOS") {
fmt.Printf("%s=%s\n", key, value)
}
}
}
fmt.Println("\n=== 练习完成 ===")
fmt.Println("请实现所有TODO标记的函数,然后运行测试验证结果")
}
测试题2:代码风格修复
go
// 练习2:代码风格修复
// 这个文件包含了多种违反Go编码规范的代码
// 请修复所有的风格问题,并将修复后的代码保存到good_style.go
package main
import(
"fmt"
"strings"
"os"
)
// 违规1: 常量命名不规范
const max_retry_count = 5
const DEFAULT_TIMEOUT=30
// 违规2: 变量命名不规范
var user_name string
var UserAge int
var HTTP_CLIENT_TIMEOUT = 60
// 违规3: 接口命名不规范
type file_handler interface{
read_file(string)([]byte,error)
write_file(string,[]byte)error
}
// 违规4: 结构体和方法命名不规范
type user_info struct{
first_name string
last_name string
email_address string
}
// 违规5: 函数命名和格式问题
func get_user_full_name(u user_info)string{
return u.first_name+" "+u.last_name
}
func process_user_data(users[]user_info)([]string,error){
var results[]string
for _,user:=range users{
if user.first_name==""{
continue
}
full_name:=get_user_full_name(user)
results=append(results,full_name)
}
return results,nil
}
// 违规6: 错误处理不规范
func read_config_file(filename string)map[string]string{
file,err:=os.Open(filename)
if err!=nil{
panic(err) // 不应该使用panic
}
defer file.Close()
config:=make(map[string]string)
// 简化的配置读取逻辑
return config
}
// 违规7: 导出函数但没有文档注释
func ProcessData(data string) string {
return strings.ToUpper(data)
}
// 违规8: 未使用的变量和导入
import _ "net/http" // 不必要的导入
func unused_function(){
var unused_var int // 未使用的变量
fmt.Println("这个函数没有被调用")
}
// 违规9: 不一致的缩进和空格
func badly_formatted_function(){
if true{
fmt.Println("bad formatting")
}else{
fmt.Println("also bad")
}
for i:=0;i<5;i++{
fmt.Printf("i=%d\n",i)
}
}
// 违规10: 包级别变量没有合适的命名
var GlobalCounter int
var global_flag bool
func main(){
fmt.Println("这是一个包含多种风格问题的示例")
fmt.Println("请修复所有问题并重新组织代码")
user:=user_info{
first_name:"John",
last_name:"Doe",
email_address:"john@example.com",
}
full_name:=get_user_full_name(user)
fmt.Printf("用户全名: %s\n",full_name)
config:=read_config_file("config.txt")
fmt.Printf("配置: %v\n",config)
processed:=ProcessData("hello world")
fmt.Printf("处理结果: %s\n",processed)
}
// TODO: 修复以下问题
// 1. 修复所有命名规范问题(变量、函数、常量、接口、结构体)
// 2. 添加合适的文档注释
// 3. 修复格式化问题(空格、缩进、换行)
// 4. 改进错误处理
// 5. 删除未使用的变量和导入
// 6. 确保导出的标识符有文档注释
// 7. 遵循Go的习惯用法
测试题3:项目结构组织
go
// Package main 演示Go项目结构组织的最佳实践
// 练习3:项目结构组织
package main
import (
"fmt"
"os"
"path/filepath"
)
// 练习任务:
// 1. 创建标准的Go项目目录结构
// 2. 理解各个目录的作用和命名规范
// 3. 实现项目结构检查工具
// ProjectStructure 表示项目结构信息
type ProjectStructure struct {
RootPath string
Directories map[string]DirectoryInfo
Files map[string]FileInfo
}
// DirectoryInfo 目录信息
type DirectoryInfo struct {
Path string
Purpose string
IsRequired bool
Permissions os.FileMode
}
// FileInfo 文件信息
type FileInfo struct {
Path string
Purpose string
IsRequired bool
Permissions os.FileMode
}
// StandardGoProjectStructure 返回标准Go项目结构
func StandardGoProjectStructure() ProjectStructure {
return ProjectStructure{
Directories: map[string]DirectoryInfo{
"cmd": {
Path: "cmd/",
Purpose: "应用程序入口点,包含main包",
IsRequired: false,
Permissions: 0755,
},
"internal": {
Path: "internal/",
Purpose: "私有代码,不能被其他项目导入",
IsRequired: false,
Permissions: 0755,
},
"pkg": {
Path: "pkg/",
Purpose: "可以被其他项目导入的库代码",
IsRequired: false,
Permissions: 0755,
},
"api": {
Path: "api/",
Purpose: "API定义文件(OpenAPI/Swagger规范、协议定义文件)",
IsRequired: false,
Permissions: 0755,
},
"web": {
Path: "web/",
Purpose: "Web应用程序特定的组件:静态web资源、服务端模板和SPA",
IsRequired: false,
Permissions: 0755,
},
"configs": {
Path: "configs/",
Purpose: "配置文件模板或默认配置",
IsRequired: false,
Permissions: 0755,
},
"init": {
Path: "init/",
Purpose: "系统初始化(systemd、upstart、sysv)和进程管理器(runit、supervisord)配置",
IsRequired: false,
Permissions: 0755,
},
"scripts": {
Path: "scripts/",
Purpose: "执行各种构建、安装、分析等操作的脚本",
IsRequired: false,
Permissions: 0755,
},
"build": {
Path: "build/",
Purpose: "打包和持续集成",
IsRequired: false,
Permissions: 0755,
},
"deployments": {
Path: "deployments/",
Purpose: "IaaS、PaaS、系统和容器编排部署配置和模板",
IsRequired: false,
Permissions: 0755,
},
"test": {
Path: "test/",
Purpose: "额外的外部测试应用程序和测试数据",
IsRequired: false,
Permissions: 0755,
},
"docs": {
Path: "docs/",
Purpose: "设计和用户文档",
IsRequired: false,
Permissions: 0755,
},
"tools": {
Path: "tools/",
Purpose: "此项目的支持工具",
IsRequired: false,
Permissions: 0755,
},
"examples": {
Path: "examples/",
Purpose: "应用程序或公共库的示例",
IsRequired: false,
Permissions: 0755,
},
"third_party": {
Path: "third_party/",
Purpose: "外部辅助工具,分叉代码和其他第三方工具",
IsRequired: false,
Permissions: 0755,
},
"githooks": {
Path: "githooks/",
Purpose: "Git钩子",
IsRequired: false,
Permissions: 0755,
},
"assets": {
Path: "assets/",
Purpose: "与存储库一起使用的其他资源",
IsRequired: false,
Permissions: 0755,
},
},
Files: map[string]FileInfo{
"go.mod": {
Path: "go.mod",
Purpose: "Go模块定义文件",
IsRequired: true,
Permissions: 0644,
},
"go.sum": {
Path: "go.sum",
Purpose: "Go模块校验和文件",
IsRequired: false,
Permissions: 0644,
},
"README.md": {
Path: "README.md",
Purpose: "项目说明文档",
IsRequired: true,
Permissions: 0644,
},
"LICENSE": {
Path: "LICENSE",
Purpose: "项目许可证",
IsRequired: false,
Permissions: 0644,
},
".gitignore": {
Path: ".gitignore",
Purpose: "Git忽略文件配置",
IsRequired: true,
Permissions: 0644,
},
"Makefile": {
Path: "Makefile",
Purpose: "构建脚本",
IsRequired: false,
Permissions: 0644,
},
"Dockerfile": {
Path: "Dockerfile",
Purpose: "Docker镜像构建文件",
IsRequired: false,
Permissions: 0644,
},
},
}
}
// ProjectStructureChecker 项目结构检查器
type ProjectStructureChecker struct {
rootPath string
structure ProjectStructure
}
// NewProjectStructureChecker 创建项目结构检查器
func NewProjectStructureChecker(rootPath string) *ProjectStructureChecker {
return &ProjectStructureChecker{
rootPath: rootPath,
structure: StandardGoProjectStructure(),
}
}
// CheckProjectStructure 检查项目结构
// TODO: 实现项目结构检查功能
func (psc *ProjectStructureChecker) CheckProjectStructure() ([]string, []string, error) {
// 返回:存在的目录/文件列表,缺失的必需项列表,错误
// 你的代码在这里
return nil, nil, fmt.Errorf("未实现")
}
// CreateProjectStructure 创建标准项目结构
// TODO: 实现创建项目结构功能
func (psc *ProjectStructureChecker) CreateProjectStructure() error {
// 创建标准的Go项目目录结构
// 你的代码在这里
return fmt.Errorf("未实现")
}
// ValidateDirectoryNaming 验证目录命名规范
// TODO: 实现目录命名验证功能
func (psc *ProjectStructureChecker) ValidateDirectoryNaming() ([]string, error) {
// 检查目录命名是否符合Go项目规范
// 返回违规的目录列表
// 你的代码在这里
return nil, fmt.Errorf("未实现")
}
// GenerateProjectReport 生成项目结构报告
// TODO: 实现项目报告生成功能
func (psc *ProjectStructureChecker) GenerateProjectReport() (string, error) {
// 生成详细的项目结构分析报告
// 你的代码在这里
return "", fmt.Errorf("未实现")
}
// 辅助函数:检查路径是否存在
func pathExists(path string) bool {
_, err := os.Stat(path)
return !os.IsNotExist(err)
}
// 辅助函数:检查是否为目录
func isDirectory(path string) bool {
info, err := os.Stat(path)
if err != nil {
return false
}
return info.IsDir()
}
// 辅助函数:获取目录下的所有文件和目录
func listDirectoryContents(path string) ([]string, error) {
var contents []string
err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
contents = append(contents, path)
return nil
})
return contents, err
}
// 示例项目结构创建器
type ProjectCreator struct {
projectName string
rootPath string
}
// NewProjectCreator 创建项目创建器
func NewProjectCreator(projectName, rootPath string) *ProjectCreator {
return &ProjectCreator{
projectName: projectName,
rootPath: rootPath,
}
}
// CreateWebAppProject 创建Web应用项目结构
// TODO: 实现Web应用项目创建功能
func (pc *ProjectCreator) CreateWebAppProject() error {
// 创建适合Web应用的项目结构
// 你的代码在这里
return fmt.Errorf("未实现")
}
// CreateLibraryProject 创建库项目结构
// TODO: 实现库项目创建功能
func (pc *ProjectCreator) CreateLibraryProject() error {
// 创建适合库的项目结构
// 你的代码在这里
return fmt.Errorf("未实现")
}
// CreateCLIProject 创建命令行工具项目结构
// TODO: 实现CLI项目创建功能
func (pc *ProjectCreator) CreateCLIProject() error {
// 创建适合命令行工具的项目结构
// 你的代码在这里
return fmt.Errorf("未实现")
}
func main() {
fmt.Println("=== Go项目结构组织练习 ===")
// 示例:检查当前项目结构
currentDir, _ := os.Getwd()
checker := NewProjectStructureChecker(currentDir)
fmt.Printf("检查项目结构:%s\n", currentDir)
// 显示标准项目结构说明
structure := StandardGoProjectStructure()
fmt.Println("\n=== 标准Go项目目录结构 ===")
for name, info := range structure.Directories {
required := ""
if info.IsRequired {
required = " (必需)"
}
fmt.Printf("📁 %s%s\n %s\n", info.Path, required, info.Purpose)
}
fmt.Println("\n=== 标准Go项目文件 ===")
for name, info := range structure.Files {
required := ""
if info.IsRequired {
required = " (必需)"
}
fmt.Printf("📄 %s%s\n %s\n", info.Path, required, info.Purpose)
}
fmt.Println("\n=== 练习任务 ===")
fmt.Println("1. 实现 CheckProjectStructure() 方法")
fmt.Println("2. 实现 CreateProjectStructure() 方法")
fmt.Println("3. 实现 ValidateDirectoryNaming() 方法")
fmt.Println("4. 实现 GenerateProjectReport() 方法")
fmt.Println("5. 实现不同类型项目的创建方法")
fmt.Println("\n请完成所有TODO标记的函数,然后运行测试验证结果")
}
测试题4:单元测试和基准测试
go
// Package testing 演示Go语言测试的最佳实践
// 练习4:单元测试和基准测试
package main
import (
"errors"
"fmt"
"math"
)
// Calculator 计算器结构体
type Calculator struct {
history []Operation
}
// Operation 表示一个计算操作
type Operation struct {
Operator string
Operand1 float64
Operand2 float64
Result float64
}
// NewCalculator 创建新的计算器实例
func NewCalculator() *Calculator {
return &Calculator{
history: make([]Operation, 0),
}
}
// Add 加法运算
func (c *Calculator) Add(a, b float64) float64 {
result := a + b
c.recordOperation("+", a, b, result)
return result
}
// Subtract 减法运算
func (c *Calculator) Subtract(a, b float64) float64 {
result := a - b
c.recordOperation("-", a, b, result)
return result
}
// Multiply 乘法运算
func (c *Calculator) Multiply(a, b float64) float64 {
result := a * b
c.recordOperation("*", a, b, result)
return result
}
// Divide 除法运算
func (c *Calculator) Divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("除数不能为零")
}
result := a / b
c.recordOperation("/", a, b, result)
return result, nil
}
// Power 幂运算
func (c *Calculator) Power(base, exponent float64) float64 {
result := math.Pow(base, exponent)
c.recordOperation("^", base, exponent, result)
return result
}
// Sqrt 平方根运算
func (c *Calculator) Sqrt(x float64) (float64, error) {
if x < 0 {
return 0, errors.New("负数没有实数平方根")
}
result := math.Sqrt(x)
c.recordOperation("√", x, 0, result)
return result, nil
}
// recordOperation 记录操作历史
func (c *Calculator) recordOperation(operator string, operand1, operand2, result float64) {
op := Operation{
Operator: operator,
Operand1: operand1,
Operand2: operand2,
Result: result,
}
c.history = append(c.history, op)
}
// GetHistory 获取计算历史
func (c *Calculator) GetHistory() []Operation {
return c.history
}
// ClearHistory 清空计算历史
func (c *Calculator) ClearHistory() {
c.history = c.history[:0]
}
// GetLastResult 获取最后一次计算结果
func (c *Calculator) GetLastResult() (float64, error) {
if len(c.history) == 0 {
return 0, errors.New("没有计算历史")
}
return c.history[len(c.history)-1].Result, nil
}
// 数学工具函数
// Factorial 计算阶乘
func Factorial(n int) (int, error) {
if n < 0 {
return 0, errors.New("负数没有阶乘")
}
if n == 0 || n == 1 {
return 1, nil
}
result := 1
for i := 2; i <= n; i++ {
result *= i
}
return result, nil
}
// Fibonacci 计算斐波那契数列的第n项
func Fibonacci(n int) (int, error) {
if n < 0 {
return 0, errors.New("索引不能为负数")
}
if n == 0 {
return 0, nil
}
if n == 1 {
return 1, nil
}
a, b := 0, 1
for i := 2; i <= n; i++ {
a, b = b, a+b
}
return b, nil
}
// IsPrime 判断是否为素数
func IsPrime(n int) bool {
if n < 2 {
return false
}
if n == 2 {
return true
}
if n%2 == 0 {
return false
}
limit := int(math.Sqrt(float64(n)))
for i := 3; i <= limit; i += 2 {
if n%i == 0 {
return false
}
}
return true
}
// GCD 计算最大公约数
func GCD(a, b int) int {
for b != 0 {
a, b = b, a%b
}
return a
}
// LCM 计算最小公倍数
func LCM(a, b int) int {
return a * b / GCD(a, b)
}
// Sum 计算切片中所有数字的和
func Sum(numbers []int) int {
total := 0
for _, num := range numbers {
total += num
}
return total
}
// Average 计算平均值
func Average(numbers []float64) (float64, error) {
if len(numbers) == 0 {
return 0, errors.New("空切片没有平均值")
}
sum := 0.0
for _, num := range numbers {
sum += num
}
return sum / float64(len(numbers)), nil
}
// Max 找到切片中的最大值
func Max(numbers []int) (int, error) {
if len(numbers) == 0 {
return 0, errors.New("空切片没有最大值")
}
max := numbers[0]
for _, num := range numbers[1:] {
if num > max {
max = num
}
}
return max, nil
}
// Min 找到切片中的最小值
func Min(numbers []int) (int, error) {
if len(numbers) == 0 {
return 0, errors.New("空切片没有最小值")
}
min := numbers[0]
for _, num := range numbers[1:] {
if num < min {
min = num
}
}
return min, nil
}
// SlowFibonacci 低效的斐波那契实现(用于基准测试对比)
func SlowFibonacci(n int) int {
if n <= 1 {
return n
}
return SlowFibonacci(n-1) + SlowFibonacci(n-2)
}
func main() {
fmt.Println("=== Go单元测试练习 ===")
// 创建计算器实例
calc := NewCalculator()
// 演示基本操作
fmt.Printf("5 + 3 = %.2f\n", calc.Add(5, 3))
fmt.Printf("10 - 4 = %.2f\n", calc.Subtract(10, 4))
fmt.Printf("6 * 7 = %.2f\n", calc.Multiply(6, 7))
if result, err := calc.Divide(15, 3); err != nil {
fmt.Printf("除法错误: %v\n", err)
} else {
fmt.Printf("15 / 3 = %.2f\n", result)
}
// 演示数学函数
if fact, err := Factorial(5); err != nil {
fmt.Printf("阶乘错误: %v\n", err)
} else {
fmt.Printf("5! = %d\n", fact)
}
if fib, err := Fibonacci(10); err != nil {
fmt.Printf("斐波那契错误: %v\n", err)
} else {
fmt.Printf("第10项斐波那契数: %d\n", fib)
}
fmt.Printf("17是素数吗? %t\n", IsPrime(17))
fmt.Printf("GCD(48, 18) = %d\n", GCD(48, 18))
numbers := []int{1, 2, 3, 4, 5}
fmt.Printf("数组和: %d\n", Sum(numbers))
fmt.Println("\n=== 练习任务 ===")
fmt.Println("1. 为所有函数编写单元测试")
fmt.Println("2. 测试边界条件和错误情况")
fmt.Println("3. 编写表驱动测试")
fmt.Println("4. 编写基准测试")
fmt.Println("5. 使用测试覆盖率工具")
fmt.Println("6. 编写示例测试")
fmt.Println("\n运行测试命令:")
fmt.Println("go test -v")
fmt.Println("go test -bench=.")
fmt.Println("go test -cover")
fmt.Println("go test -coverprofile=coverage.out")
fmt.Println("go tool cover -html=coverage.out")
}
测试题5:构建、跨平台编译和部署
go
// Package main 演示Go构建和部署的最佳实践
// 练习5:构建、跨平台编译和部署
package main
import (
"flag"
"fmt"
"log"
"net/http"
"os"
"runtime"
"time"
"github.com/gin-gonic/gin"
)
// 构建信息变量(通过ldflags在构建时注入)
var (
Version = "dev" // 版本号
BuildTime = "unknown" // 构建时间
GitCommit = "unknown" // Git提交哈希
GoVersion = runtime.Version() // Go版本
)
// Config 应用配置
type Config struct {
Port string
Environment string
LogLevel string
}
// parseFlags 解析命令行参数
func parseFlags() *Config {
config := &Config{}
flag.StringVar(&config.Port, "port", "8080", "服务器端口")
flag.StringVar(&config.Environment, "env", "development", "运行环境 (development/production)")
flag.StringVar(&config.LogLevel, "log-level", "info", "日志级别 (debug/info/warn/error)")
version := flag.Bool("version", false, "显示版本信息")
flag.Parse()
if *version {
printVersion()
os.Exit(0)
}
return config
}
// printVersion 打印版本信息
func printVersion() {
fmt.Printf("应用版本: %s\n", Version)
fmt.Printf("构建时间: %s\n", BuildTime)
fmt.Printf("Git提交: %s\n", GitCommit)
fmt.Printf("Go版本: %s\n", GoVersion)
fmt.Printf("操作系统: %s\n", runtime.GOOS)
fmt.Printf("架构: %s\n", runtime.GOARCH)
}
// setupRouter 设置路由
func setupRouter(config *Config) *gin.Engine {
// 根据环境设置Gin模式
if config.Environment == "production" {
gin.SetMode(gin.ReleaseMode)
}
r := gin.Default()
// 健康检查端点
r.GET("/health", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"status": "ok",
"timestamp": time.Now().Unix(),
})
})
// 版本信息端点
r.GET("/version", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"version": Version,
"build_time": BuildTime,
"git_commit": GitCommit,
"go_version": GoVersion,
"os": runtime.GOOS,
"arch": runtime.GOARCH,
})
})
// 系统信息端点
r.GET("/info", func(c *gin.Context) {
var m runtime.MemStats
runtime.ReadMemStats(&m)
c.JSON(http.StatusOK, gin.H{
"goroutines": runtime.NumGoroutine(),
"memory_alloc": m.Alloc,
"memory_total": m.TotalAlloc,
"memory_sys": m.Sys,
"gc_runs": m.NumGC,
"environment": config.Environment,
"log_level": config.LogLevel,
})
})
// API路由组
api := r.Group("/api/v1")
{
api.GET("/ping", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "pong",
"time": time.Now(),
})
})
api.GET("/platform", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"os": runtime.GOOS,
"arch": runtime.GOARCH,
"num_cpu": runtime.NumCPU(),
"go_version": runtime.Version(),
"compiler": runtime.Compiler,
})
})
}
return r
}
// gracefulShutdown 优雅关闭服务器
func gracefulShutdown(server *http.Server) {
// 这里可以添加信号处理逻辑
// 为简化示例,直接启动服务器
log.Printf("服务器启动在端口 %s", server.Addr)
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf("服务器启动失败: %v", err)
}
}
func main() {
// 解析命令行参数
config := parseFlags()
// 打印启动信息
fmt.Printf("=== Go构建部署练习应用 ===\n")
fmt.Printf("版本: %s\n", Version)
fmt.Printf("环境: %s\n", config.Environment)
fmt.Printf("端口: %s\n", config.Port)
fmt.Printf("平台: %s/%s\n", runtime.GOOS, runtime.GOARCH)
fmt.Println("========================")
// 设置路由
router := setupRouter(config)
// 创建HTTP服务器
server := &http.Server{
Addr: ":" + config.Port,
Handler: router,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 60 * time.Second,
}
// 启动服务器
gracefulShutdown(server)
}
// 练习任务:
// 1. 使用go build构建应用
// 2. 使用ldflags注入构建信息
// 3. 跨平台编译(Windows、Linux、macOS)
// 4. 创建Docker镜像
// 5. 编写构建脚本
// 6. 实现版本管理
// 7. 配置CI/CD流水线