做视频的背景音乐哪里下载网站,网络营销模式下品牌推广研究,网络公司做网站后期注意,企业管理系统代码对于一个像我这样没有go背景的java程序员来说#xff0c;使用go开发一个可用的程序的速度是肉眼可见的缓慢。 其难点不在于go语言本身#xff0c;而是搭建整个工程链路的过程#xff0c;即所谓的“配环境”。 本文主要讲述如何配出一个适合go开发的环境#xff0c;以免有同… 对于一个像我这样没有go背景的java程序员来说使用go开发一个可用的程序的速度是肉眼可见的缓慢。 其难点不在于go语言本身而是搭建整个工程链路的过程即所谓的“配环境”。 本文主要讲述如何配出一个适合go开发的环境以免有同事陷入困境时对我使出“您配吗”之类的大招。 假如拿到一台新电脑 安装brew/bin/bash-c$(curl-fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)安装完成后可以执行 brew--version 查看brew是否安装成功。 安装go编译器和调试器 ▐ 安装go编译器 brew install go这将安装go的最新版本。在发文的这一刻go的最新版本是1.22。如果想要安装某个特定的go历史版本可以使用brew install go1.21这将安装go1.21。可以使用brew search go来查看当前brew仓库中可用的go版本列表。安装完成后可以执行 go version 查看go是否安装成功。 ▐ 安装go调试器 brew install delvedelve可以理解为是go版本的gdb。brew install gdb如果遇到delve搞不定的场景就需要gdb出来救场了。安装完成后可以执行 dlv version 查看delve是否安装成功执行 gdb --version 查看gdb是否安装成功。 ▐ 配置 go 在编译产物中附加上调试信息 在shell脚本.bash_profile或.zshrc中添加一行 export GOFLAGS-ldflags-compressdwarffalse ▐ 配置github gfw代理 在shell脚本.bash_profile或.zshrc中添加一行 export GOPROXYhttps://goproxy.io,direct ▐ 配置私有代码仓库 在shell脚本.bash_profile或.zshrc中添加一行 export GOPRIVATE你的私有gitlab地址.com/*,另外的私有gitlab地址.com/* 不要带http或https前缀 安装ide 隆重推荐goland真的好用但是要花钱。其次推荐idea安装go插件但是要求idea是Ultimate版本。不想花钱的话可以用vscode。 vscode的必装插件Go 认准Microsoft出品。 工程结构 如果开发的是一个独立运行的程序存在main函数推荐的目录结构如下 your_app_name/
├── cmd/
│ ├── your_app_name/ # 应用程序的入口点包含main包
│ │ └── main.go # 应用程序的主函数所在
│ └── ... # 如果有多个可执行文件可以在这里添加
├── internal/ # 可选存放仅供本应用内部使用的包
│ └── ... # 内部包结构比如业务逻辑、工具函数等
├── config/ # 配置文件或配置加载逻辑
│ └── ... # 如yaml, toml, env等配置文件
├── scripts/ # 构建、部署脚本等
│ └── ...
├── tests/ # 单元测试、集成测试等
│ └── ...
├── README.md # 项目说明文档
├── go.mod # Go模块定义文件
├── go.sum # Go模块依赖的校验和文件
├── .gitignore # Git忽略规则文件
└── ... # 其他必要的文件如Dockerfile、Makefile等 如果开发的是一个给别人用的类库推荐的目录结构如下 your_library_name/
├── internal/ # 可选用于存放不希望对外暴露的包
│ └── ... # 内部使用的包
├── pkg/ # 存放库的公开对外接口。pkg 这一层可以省略直接把源代码放在/your_library_name 目录下
│ └── your_library_name/
│ ├── your_library.go
│ └── ... # 库的各个源文件
├── tests/ # 单元测试、集成测试等
│ └── ...
├── README.md # 项目说明文档包括安装、使用方法等
├── go.mod # Go模块定义文件
├── go.sum # Go模块的校验和文件
├── .gitignore # Git忽略文件列表
└── ... # 其他必要的文件如Dockerfile、Makefile等 依赖管理 go的依赖项通过 go.mod 文件描述类似于java的 pom.xml 或py的 requirements.txt go是源代码依赖没有制品的概念。可以理解为每次编译时go都会从git上面把所有的依赖项的源代码全部拉下来放在一起编译。官方的源代码仓库就是github。 一个典型的go.mod示例如下 module github.com/dapr/dapr
^^^ 声明该模块的名字类似于 groupId:artifactId强烈建议在这里填写这个工程的实际可访问的git地址否则会带来无穷无尽的麻烦go 1.21
^^^ 指定要求的最低 go 版本类似于 java.version1.8/java.versionrequire (
^^^ 这里列出所有直接依赖项类似于 dependenciescontrib.go.opencensus.io/exporter/prometheus v0.4.2github.com/PaesslerAG/jsonpath v0.1.1github.com/PuerkitoBio/purell v1.2.1
)require (
^^^ 这一大片后面带有 // indirect 的是 go 自动生成的所有间接依赖类似 mvn dependency:tree 的产出。千万不要手工修改这部分。cloud.google.com/go v0.110.10 // indirectcloud.google.com/go/compute v1.23.3 // indirectcloud.google.com/go/compute/metadata v0.2.3 // indirectcloud.google.com/go/datastore v1.15.0 // indirectcloud.google.com/go/iam v1.1.5 // indirect
)replace (
^^^ 这一段用于模块的名称和实际 git 地址不匹配的情况。上面提到的无穷无尽的麻烦就是指所有引用你的包的项目都需要使用 replace 来将你的包指向实际的 git 地址github.com/toolkits/concurrent github.com/niean/gotools v0.0.0-201512replace github.com/dapr/components-contrib ../components-contrib^^^ 也可以将模块的路径指向本地以便于二方包开发过程中进行调试
) 当工程的多个依赖项发生冲突时比如说app依赖lib1和lib2lib1依赖libaaa的 1.0版本lib2依赖libaaa的2.0版本go不会进行仲裁会直接报编译错。你需要在go.mod中手工指定libaaa到底应当使用哪个版本。 当依赖的二方包并没有放在github上而是放在自建的gitlab上时直接编译是编不过的即使你有对应 gitlab 仓库的权限。 这是因为go在编译时并不是真的去直接拉git而是会去尝试访问一个代理服务器类似于cdn。你需要指定go在访问我们自己的git时不要走官方的cdn因为那上面肯定没有我们集团内部的包。 如果遇到这种情况就需要在shell脚本.bash_profile或.zshrc中添加一行 export GOPRIVATE你的私有gitlab地址.com/*,另外的私有gitlab地址.com/*这在第1节中已经讲过。 当依赖的二方包的owner修改了git的访问权限配置导致你没有权限访问其代码仓库时编译会失败。除了找项目owner开权限之外没有任何办法。 在代码中引用二方包 首先必须要说go的import体系对于java程序员来说是非常难以上手的。主要体现在如下几个方面 ▐ 时刻注意区分清楚【模块 / module】和【包 / package】的概念 这个在java中根本不是问题没人会弄混。但是在go中经常会造成混淆因为这两者在go里面看起来长得差不多。以及go的import语句和java的import有本质的区别你更应当把go的import理解为c语言的#include。 【模块】指的是一个库类似于一个jar包其名称是groupId:artifactId对应的git地址只在go.mod中出现。 模块的名称通常等同于其git地址形式为 github.com/groupId/artifactId 具体来说一个典型的模块名大概类似于 github.com/apache/dubbo-go在域名后面只有两段groupId 和 artifactId 【包】指的是把相关联的文件放在一起的集合类似于java概念中的package 具体来说一个在import语句后面跟的典型的包路径大概类似于 github.com/apache/dubbo-go/remoting 其中的 github.com/apache/dubbo-go 部分是模块名后面的 /remoting 表示这个包所处的具体git路径。 再次强调请一定要抛开java的import语义将go的import直接理解成#include 如果遇到依赖相关的难以理解的编译错误请检查是否误将模块路径放在了import语句里面或者是不是把包路径误放在了go.mod里。 ▐ import包时是import包的git地址但是这个地址和包的名称可以不一致 对于 java 程序员来说有一个冷知识在常见的语言中只有java强行规定了包名必须和目录结构一致、类名必须和文件名一致而go并没有这条规定。所以import一个包时这个包在实际代码中使用的名称和包的路径可以完全看不出任何关系。 从人道主义角度来讲非常不推荐向别人提供这样的包但也只是不推荐而已。 比如 import (github.com/go-playground/validator/v10
)
...
func foo() {validator.Xxx()
} 引用这个包时需要依赖包的路径 github.com/go-playground/validator/v10但是在具体使用的时候使用的包名是validator这中间看不出任何对应关系只能去翻源代码。个人建议除了标准库的包之外对所有import的包都自己定义一个别名例如 import (validator github.com/go-playground/validator/v10
) ▐ go在import中引入的包在代码中必须被使用否则编译会报错 在ide中默认会把没使用的包对应的import语句直接删掉。所以如果临时注释掉一条语句再回头把注释去掉时很有可能因为import语句被删掉了而编译不过。个人建议当临时需要禁用掉某些代码时不要直接注释要使用if false {} 给包起来。 if false {validator.Xxx() // 不要直接注掉免得ide把对应的import语句也给删了
} ▐ 修改go.mod后必须执行一次go mod tidy 当要新增/删除依赖时需要修改go.mod文件类似于修改pom.xml。在修改之后需要手工执行 go mod tidy否则会编译失败。go不会在编译时帮你更新依赖。顺便受上一条规则影响所有的import都必须是实际被使用的。如果代码中去掉了某个import而这一行import是整个工程中唯一引用某个依赖的位置那么就意味着这个依赖不再被需要。此时需要从go.mod中去掉该依赖并执行 go mod tidy否则会导致编译不通过。个人建议直接把go mod tidy命令放在编译脚本中每次编译时都执行一下。下面【编译】一节会详细解释。 ▐ 执行过go mod tidy之后 go.mod文件本身会被修改 go mod tidy会原地修改go.mod把所有间接依赖也明确地标在原文件中。 如果go.mod中声明的依赖没有被实际使用go mod tidy会直接把这一行require给删掉。 这一条规则尤其坑爹。前面提到了go要求代码中所有import进来的包都必须被使用。如果你注掉了一行代码很有可能导致IDE把对应的import删掉然后go mod tidy会把go.mod中的依赖声明给删掉。这样你再把注释恢复回去之后就需要从go.mod改起。 个人建议每次执行过 go mod tidy 之后都要记得检查一下go.mod文件以免被go mod tidy命令改坏。以及再重申一次千万不要碰go.mod里面标了 // indirect的那一片自动生成的require指令。 最后再重复一遍之前提到过的个人建议当临时需要禁用掉某些代码时不要直接注释要使用if false {} 给包起来。 向别人提供二方包 和maven一样当向别人提供二方包时我们需要向用户提供二方包的GAV坐标。 其中GroupId、ArtifactId是被包含在git repo的地址中的形式为 gitlab.mycompany.com/${groupId}/${artifactId} 之前已经强调过这个地址必须是可以被直接访问的里面放的就是二方包的源代码并且要配置好合适的访问权限。 不建议将git repo设置为除了PUBLIC之外的任何级别除非你能明确地管控所有下游使用场景。否则但凡你的包被别人引用了就永远会有不知道哪的人过来找你开权限。 Version比较特殊我们分成正式包和snapshot包两种情况来讨论。 ▐ 正式包的发版是通过git的tag机制来实现的 当一个版本开发完成时我们需要在git repo里面把最新版本的代码打一个tag名称需要遵循SemVer规范。 业务方可以使用下述语法在go.mod中依赖这个包require gitlab.mycompany.com/${groupId}/${artifactId} v$tag 例如require gitlab.mycompany.com/shop/libaaa v0.3.6-rc9 ▐ snapshot包的发版是通过git的branch机制实现的 当一个版本仍在持续开发过程中时我们可以把正在开发的分支直接公布出去 业务方可以使用下述语法在go.mod中依赖这个包 require gitlab.mycompany.com/${groupId}/${artifactId} v0.0.0-notexist
replace gitlab.mycompany.com/${groupId}/${artifactId} gitlab.mycompany.com/${groupId}/${artifactId} v0.0.0-${branch} 例如 require gitlab.mycompany.com/shop/libaaa v0.0.0-notexist
replace gitlab.mycompany.com/shop/libaaa gitlab.mycompany.com/shop/libaaa v0.0.0-develop2 类似于maven的snapshot包如果上游向分支里push了新代码下游需要重新执行 go get -u类似于mvn -U命令更新所有snapshot。 这里也可以看到go的snapshot机制叠加上基于源代码的依赖机制比mvn的 snapshot二方包要危险得多。你甚至可以向分支中提交一段编译不过的代码从而让所有下游的编译过程全部炸掉。maven好歹总得先编译个jar包出来。 总结一下如果我们开发好了一个二方包需要提供给别人使用那么需要公布两个信息 二方包的git repo地址形式为 gitlab.mycompany.com/${groupId}/${artifactId}如果是正式包需要公布其tag使用SemVer格式如果是snapshot需要公布其branch没有命名格式要求 编译 沧海月明珠有泪蓝田日暖玉生烟。
此情可待成追忆只是当时已惘然。—— 唐李商隐 离开了maven的温室之后我们必须直面go build的冰冷现实了。 go的编译命令是 go build。它有很多参数非常灵活但是每次编译都把完整命令全部敲一遍的话精神方面可能就有点问题了。这个时候我们需要用make来简化构建工作这又是一个大坑。 在java世界中我们熟悉的构建工具就是Maven。Maven预先定义了 validate compile package testdeploy 之类的阶段直接敲 mvn clean build 即可让 maven 完成预先定义的动作。 而make没有提供任何预定义的阶段在敲下 make clean build 之后要执行什么操作都需要在Makefile中手工声明。这份Makefile应当放在工程根目录下文件名即为 Makefile 八个字母注意大小写。 这里仅给出一份个人推荐的Makefile文件样例具体使用时请酌情修改 # 定义一些常量
APPNAME : your_application_name
BINDIR : /build/bin
GOBIN : $(shell go env GOPATH)/bin
export GO111MODULE : on# 目标: 清理
clean:rm -rf $(BINDIR)/*echo Cleanup completed.# 目标: 构建
build: go_mod_tidy compile# 执行go mod tidy
go_mod_tidy:go mod tidyecho go mod tidy completed.# 编译项目
compile: mkdir -p $(BINDIR)go build -o $(BINDIR)/${APPNAME}echo Build completed.# 使用帮助信息
help:echo Usage:echo make build - 整理模块依赖编译项目将产出物放到 /build/bin 目录下echo make clean - 清理构建产物.PHONY: clean build go_mod_tidy compile help make build 整理模块依赖编译项目将产出物放到 /build/bin目录下make clean 清理构建产物make help 输出上述说明 调试 首先需要重申一个常识对于go这种编译型语言来说“调试”这个动作是面向可执行程序即编译的产物的而不是面向源代码的。 如果是在vscode中调试需要修改项目 /.vscode目录中的launch.json文件以指定待调试的可执行程序的位置、运行该程序时需要传递的参数和需设置的环境变量等信息。 {version: 0.2.0,configurations: [{name: Launch Go Program with Args,type: go,request: launch,mode: debug,program: ${fileDirname}, // 当前文件所在的目录作为工作目录如果你需要指定特定的可执行文件路径可以改为该路径args: [arg1, arg2, --optionvalue], // 在这里添加你的命令行参数env: {env1:env_value1, env2:env_value2}, // 可以在这里添加环境变量如果需要showLog: true, // 是否在调试控制台显示Delve的日志默认为falsetrace: verbose // 设置为verbose可以获取更详细的调试信息根据需要调整}]
} 实际的调试过程无需赘述。只能说vscode go插件又不是不能用其提供的断点和watch功能相比goland来说还是有些差距。 如果发现调试过程非常跳跃甚至不可用请检查一下是否在编译选项中配置了 -ldflags-compressdwarffalse这个参数用于在编译产物中保留debug信息。 如果因为各种原因无法在vscode环境内进行调试我们可以尝试使用delve命令行工具来进行调试。 调试命令为 dlv exec xxxx -- 要传给xxx的命令行参数要记得它调试的是编译出来的可执行文件。 delve提供的是基于命令行的交互方式。使用exec命令启动时整个程序不会开始运行而是会停在整个main函数的入口外面。 此时可以敲命令与程序进行交互常用的命令如下 b 命令 设置断点c 命令 执行至下一个断点n 命令 step overs 命令 step inso 命令 step outargs 命令 查看方法参数p 命令 查看变量的值 delve同样支持 dlv debug xxx.go 的语法可以直接指定源文件此时它会调用go编译器把这个文件编译出来之后再去调试。对于特别小的工程来说较为方便。 如果delve也搞不定就只能上gdb了。gdb具体的用法我就不讲了因为我也不熟。 打包 脱离了java/maven后我们需要重新熟悉一下linux世界中“正统”的软件分发方式。 集团最初选择了将各系统运行在centos上也就意味着集团的软件包分发是基于rpm/yum体系的。与之类似的还有Debian系的deb/apt、Archlinux使用的 tar.xz/pacman之类。 我们需要将我们的构建产物打成rpm包类似于jar包具体打rpm包的过程请学习 RPM打包操作手册。 面向ChatGPT老师教程 Q: 我需要以《面向chatgpt老师编程》为题写一篇几百字的短文向同事们介绍如何借助您的知识迅速掌握go的编程技能请帮我提供一份草稿 A: 《面向ChatGPT老师编程快速掌握Go语言技能》 在技术日新月异的今天Go语言以其简洁的语法、高效的并发模型和卓越的性能在众多编程语言中脱颖而出成为众多开发者的新宠。但对于初学者而言如何高效、系统地学习Go快速掌握其精髓却是一个值得探讨的话题。在此我们引入一位特别的“老师”——ChatGPT来指导我们如何在编程之旅中乘风破浪迅速提升Go语言技能。 第一步基础搭建从Hello World开始与ChatGPT老师的对话不妨就从最经典的“Hello, World!”程序开始。通过编写这个简单的程序ChatGPT不仅能帮你熟悉Go的基本语法还能深入浅出地解释背后的工作原理比如包的导入、函数定义等基础概念。 第二步深入理解并发模型Go语言的一大亮点是其内置的goroutine和channel机制这对于构建高性能的并发服务至关重要。通过向ChatGPT提出具体场景的问题如“如何使用goroutine处理大量并发请求”或“如何利用channel实现数据安全共享”ChatGPT能以实例结合理论的方式让你轻松掌握并发编程的核心技巧。 第三步实战演练项目驱动学习理论知识虽好但没有实践的支撑就如同空中楼阁。不妨向ChatGPT请教一些小型实战项目如编写一个简易的Web服务器、实现一个文件上传下载服务等。ChatGPT不仅会提供代码示例还会引导你思考如何优化代码结构、提高执行效率让你在实践中深刻理解Go的高级特性。 第四步调试与优化进阶之道遇到bug怎么办性能瓶颈如何突破ChatGPT在这些方面同样能给予帮助。你可以询问如何使用Go的调试工具如delve进行代码调试或是如何利用pprof进行性能分析。通过ChatGPT的指导你将学会如何高效地定位问题并进行性能调优让代码更加健壮、高效。 第五步持续学习紧跟Go生态发展Go语言的生态系统不断发展壮大新的库和框架层出不穷。ChatGPT可以帮助你追踪最新的Go语言动态推荐优秀的开源项目和文章让你的学习之路永不止步。 总之ChatGPT不仅是你的编程助手更是你学习Go语言道路上的良师益友。它以无尽的知识库、耐心的解答态度帮助你快速成长从Go语言新手进化为高手。在这个过程中记得多提问、多实践与ChatGPT老师一起探索Go语言的无限可能。 ¤ 拓展阅读 ¤ 3DXR技术 | 终端技术 | 音视频技术 服务端技术 | 技术质量 | 数据算法