实际上golang的toolchain机制就已经默默的支持了你在不同的项目中使用不同版本的go 这个需求。具体来说是从Go1.21开始支持的。
go.exe程序是如何找到与之对应的src源码的(也就是GOROOT)?
因为,在golang的目录中,go.exe在bin中,bin与src平级,所以,通过go.exe就能找到src。这就是为什么你不能随便把 go 可执行文件单独复制到别的地方用。所以,所谓的切换golang的版本就是选择不同的go可执行文件。
以上说的是正常情况,实际上,go会有一套策略来确定GOROOT的值。
优先级从高到低:
| 来源 | 说明 |
|---|---|
1. 环境变量 GOROOT |
如果你显式设置了 GOROOT=/my/go,就用这个(但通常不建议)。 |
| 2. 内置的编译时路径 | 如果没设环境变量,就使用编译时写死的路径(绝大多数情况走这里)。 |
| 3. 通过可执行文件位置推断 | 某些非官方构建可能通过 os.Executable() 获取 go 所在路径,然后向上找 src/runtime/internal/sys/zversion.go 等标志性文件来确认根目录。 |
因此,我们不能 在系统的环境变量中设置GOROOT的值,因为这样就相当于把GOROOT的值固定住了。这会导致go可执行程序与源码文件不匹配,比如

在vscode中,你会发现,编辑器的右下角显示的Go版本号明明与go.mod一致,但是代码中却提示了很多错误。当你试图切换Go版本的时候会提示
bash
GOROOT: D:\dev\php\magook\trunk\server\golang\path\pkg\mod\golang.org\toolchain@v0.0.1-go1.24.4.windows-amd64. Switching Go version when process.env["GOROOT"] is set is unsupported.
意思就是说,如果环境变量中人为设置了GOROOT,那么此处的GOROOT就是无效的。即GOROOT: D:\dev\php\magook\trunk\server\golang\path\pkg\mod\golang.org\toolchain@v0.0.1-go1.24.4.windows-amd64没有生效。实际的GOROOT还是D:\Go
还有一个地方的配置需要去掉,那就是vscode中的go.goroot,在设置->扩展->Go,找到Goroot,把go.goroot去掉,或者设置为空字符串。如果这里设置为D:\Go,那么当你试图切换Go版本的时候会提示
bash
GOROOT: D:\dev\php\magook\trunk\server\golang\path\pkg\mod\golang.org\toolchain@v0.0.1-go1.24.4.windows-amd64. Switching Go version when "go.goroot" is set is unsupported.
把这两个地方的配置删掉之后,golang环境切换就很丝滑了。
toolchain 下载的多个版本的go存放在path\pkg\mod\golang.org下面,里面有bin和src,

vscode中golang版本切换的功能是由Go扩展提供的。会根据项目中的go.mod来匹配合适的toolchain版本,于是打开vscode中的命令行,输入go version,其输出结果是对的。然而问题是,这些toolchain的bin目录并没有加入到环境变量PATH中,为什么能访问到go.exe?
实际上,这种版本切换的原理是临时修改PATH环境变量,因此只在当前命令行会话生效。
bash
> echo %PATH%
D:\dev\php\magook\trunk\server\golang\path\pkg\mod\golang.org\toolchain@v0.0.1-go1.24.4.windows-amd64\bin;d:\ProgramData\Anaconda3;d:\ProgramData\Anaconda3\Library\mi
ngw-w64\bin;d:\ProgramData\Anaconda3\Library\usr\bin;......
实际的PATH如下

也就是Go插件在PATH的开头插入了D:\dev\php\magook\trunk\server\golang\path\pkg\mod\golang.org\toolchain@v0.0.1-go1.24.4.windows-amd64\bin
在windows系统中,path里面多个条目都存在go.exe,那么以第一个匹配到的为准,不会再往后搜索。
切换完版本后,最好重启vscode,再次打开此项目后vscode机会记住你上次的设置,重构环境和服务,这样gopls,dlv,调试等操作都会运用新的环境。
在项目根目录使用 .vscode/settings.json 固化版本(可选):
json
{
"go.goroot": "D:\dev\php\magook\trunk\server\golang\path\pkg\mod\golang.org\toolchain@v0.0.1-go1.24.4.windows-amd64\bin"
}
定位到go.exe就行。