Golang中无法导入包到main.go的问题如何解决

Golang中无法导入包到main.go的问题如何解决 大家好,我遇到了一个将包导入 main.go 的问题。 我做了一个小演示来说明这个问题。 以下是文件夹结构:

YYY
|   go.mod
|   main.go
|
\---go
        api_devices.go

我运行了 go mod init devices 以及 go mod tidy,但错误仍然存在:could not import devices/go/devicemanager (no required module provides package "devices/go/devicemanager")

以下是相关文件,从 api_devices.go 开始:

package devicemanager

func Foo() string { return "TEST" }

这是 main.go

package main

import (
	"fmt"

	"devices/go/devicemanager"
)

func main() {
	fmt.Println(devicemanager.Foo())
}

这是 go.mod 文件:

module devices
go 1.25.0

我以为它应该能工作,我尝试了搜索但没找到解决我这种情况的方案。我使用的是 VS Code,如果需要的话可以提出来。如果需要更多信息请告诉我。


更多关于Golang中无法导入包到main.go的问题如何解决的实战教程也可以访问 https://www.itying.com/category-94-b0.html

12 回复

我的IDE因为安装了无数个杀毒软件而变得极其缓慢,最终卡死了。解冻之后,它又能正常工作了,我使用了“devices/go”。谢谢。

更多关于Golang中无法导入包到main.go的问题如何解决的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你好。如果你重命名了文件夹,导入路径应该只是 devices/devicemanager,不需要重复。

// 示例代码块,语言指定为go

你能详细说明一下吗?因为引用的内容提到了标准库,并且说路径中不应包含任何点号,但你却建议尝试一下。

如果你是从同一个项目中导入模块,导入路径的开头始终是 go.mod 文件中定义的模块名称。

你好。这个错误之所以发生,是因为按照惯例,文件夹的名称应该与其内部包的名称相同。因此,如果你希望它被命名为 devicemanager,请重命名文件夹。另一种方法是,你可以将导入语句改为 import devicemanager "devices/go",这同样有效,但并不常见。

@lemarkar 你好,感谢你试图提供帮助。 我确实尝试将文件夹重命名为 devicemanager 并将导入语句改为 "devices/devicemanager/devicemanager",但同样的错误仍然存在。 这非常奇怪且令人沮丧……

我从未想过,如果一个包是标准库的一部分,它的名字是否应该包含点号。这里的问题不是关于命名约定(这甚至算不上一个约定),而是因为错误的导入语句。如果你有计划将代码发布到某个地方,那么使用点号、根路径等等都是可以的;如果没有这样的计划,那么添加点号,或者更糟糕地添加“example.com”这样的域名,就没有合理的解释。

请尝试将你的内部包的边界想象为它所在的文件夹。而导入路径是一个相对路径,其中 devices 是根目录。使用像 "devices/devicemanager/devicemanager" 这样的双重名称,Go 会寻找这样的文件夹结构:

| devices
| - devicemanager
    | - devicemanager // <- Go 会在这里寻找,但你需要在上一个层级

问题不在于包名(go 是可以的),而在于模块路径

Go 标准库使用的包路径其第一路径元素不包含点号,并且 go 命令不会尝试从网络服务器解析此类路径。路径 exampletest 是为用户保留的 […]

因此,不要使用 devices,而应该使用第一路径元素中包含点号的名称。

同意。并且添加 example.com 也不会让你离能够发布这个模块更近一步(除非你拥有那个域名!)。对于本地开发,比如我在构建一个一次性使用的 Go 应用程序时(我经常把 Go 当作脚本语言使用),或者只是尝试像 JSON v2 包这样的新功能时,我经常使用 go mod init testjson 或类似的命令。

func main() {
    fmt.Println("hello world")
}

以下是一些关于包命名的补充阅读材料:

go.dev

包命名 - Go 编程语言

如何为你的包命名。

go.dev

Effective Go - Go 编程语言

将一个包命名为“go”可能不符合惯例。在业余项目中这可能无关紧要,但这里还是提一下!

Can you elaborate? Because the quote talks about STD and that paths should not contain any dots, but you say to try it.

The Go standard library uses package paths that do not contain a dot in the first path element, […]

如果你的路径第一个元素不包含点,你的代码可能会被视为 Go 标准库的一部分。

因此,“devices” 是保留的,“example.com” 则不是。

If you are importing modules from the same project, the start of the import path is always the name of the module from go.mod.

确实如此。然而,这涉及到许多工具、编辑器和其他因素。为了你自己好,至少从 “example.com” 开始,或者更好的是,从你正在实验的仓库开始。

问题出在导入路径上。你的 go.mod 中定义的模块名称是 devices,但你的包实际位于 go 子目录中,并且该目录下没有 go.mod 文件。

有两种解决方案:

方案一:修改导入路径为相对路径(推荐)

main.go 中的导入路径改为相对模块根目录的路径:

package main

import (
    "fmt"
    "devices/go" // 直接导入 go 目录
)

func main() {
    fmt.Println(devicemanager.Foo())
}

同时需要修改 api_devices.go 的包声明,使其与目录名一致:

package go // 改为 package go

func Foo() string { return "TEST" }

方案二:使用完整的模块路径

如果你希望保持 devicemanager 的包名,可以这样组织代码:

  1. 创建正确的目录结构:
YYY
├── go.mod
├── main.go
└── devicemanager
    └── api_devices.go
  1. 修改 api_devices.go
package devicemanager

func Foo() string { return "TEST" }
  1. 修改 main.go 的导入:
package main

import (
    "fmt"
    "devices/devicemanager"
)

func main() {
    fmt.Println(devicemanager.Foo())
}

方案三:使用子模块(如果 go 目录需要独立模块)

go 目录下创建独立的 go.mod

cd go
go mod init devices/go

然后更新主模块的依赖:

go mod edit -replace devices/go=./go
go mod tidy

main.go 导入保持不变:

import "devices/go/devicemanager"

建议使用方案二,这是 Go 项目最标准的组织方式。

回到顶部