Golang中为什么不使用相对导入路径?

Golang中为什么不使用相对导入路径? 我读过一些关于“相对导入路径”的资料。这在编写Go应用程序时并不常见。

那么,我该如何正确使用呢?

例如:

import (
	"app/controllers"
	"app/handlers"
	"app/helpers"
	"context"
	"database/sql"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	_ "github.com/mattn/go-sqlite3"
)
5 回复

如何标准化 app/... 包?

更多关于Golang中为什么不使用相对导入路径?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我没有看到任何相对导入,只有一些 app/... 包,这些不是标准包,因此最终可能无法工作。

相对导入至少以一个点开头。

你是什么意思?

这些并不在标准库中,而且我怀疑你能把它们加进去。

只需将它们移到一个合适的命名空间中。

在Go语言中,使用相对路径是一个代价高昂的想法,原因如下,而您刚才已经演示了其中几点:

  1. 容易与标准包混淆。(已演示)
  2. 需要额外学习如何管理相对路径包。(已演示)
  3. 会以多种方式破坏 go get 命令。(已演示)
  4. 使开发者的文档/手册变得复杂。

不以版本控制系统(vcs)URL开头的包被认为是标准包(即那些随Go编译器一起安装的包)。

在当今的Go模块中,要像导入标准包一样导入一个本地的相对路径包,您需要在 go.mod 文件中定义 replace 语句。模式如下:

replace (
        <import path> => <relative path>
)

示例:

replace (
        relative/core12 => ../core12
)

然后,在您的源代码中,就可以像这样自然地导入:

import (
        "relative/core12"
)

这并不是推荐的做法。实际上,这是一种变通方案,是对特性的滥用。推荐的做法是使用 internal 目录,这样您可以逐步抽象您的软件库,并有可能将其导出为一个独立的包。

https://golang.org/doc/go1.4#internalpackages

在Go语言中,相对导入路径确实不推荐使用,主要原因有以下几点:

  1. 可移植性差:相对路径依赖于当前工作目录,在不同环境下容易出错
  2. 模块兼容性:Go模块(go.mod)要求使用绝对导入路径
  3. 工具链支持:Go工具链(如gopls、go vet等)对绝对路径有更好的支持

正确做法是使用基于模块的绝对导入路径。以下是示例:

// go.mod
module myapp

go 1.21

require github.com/mattn/go-sqlite3 v1.14.17
// main.go
package main

import (
    "context"
    "database/sql"
    "fmt"
    "log"
    "net/http"
    "os"
    "os/signal"
    "syscall"
    "time"

    "myapp/controllers"    // 基于模块根目录的绝对路径
    "myapp/handlers"       // 基于模块根目录的绝对路径
    "myapp/helpers"        // 基于模块根目录的绝对路径
    
    _ "github.com/mattn/go-sqlite3"
)

func main() {
    // 应用代码
    db, err := sql.Open("sqlite3", "./test.db")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()
    
    // 使用本地包
    controller := controllers.NewUserController(db)
    handler := handlers.NewAuthHandler()
    
    fmt.Println("应用启动成功")
}

项目结构应该是:

myapp/
├── go.mod
├── go.sum
├── main.go
├── controllers/
│   └── user.go
├── handlers/
│   └── auth.go
└── helpers/
    └── utils.go

在Go模块系统中,所有导入都基于go.mod文件中定义的模块名称。这种方式的优势包括:

  1. 明确的依赖关系:所有导入路径都是确定的
  2. 版本控制友好:与Git等版本控制系统配合良好
  3. 构建一致性:在不同机器和环境中构建结果一致

如果确实需要使用相对路径(如测试场景),可以使用点导入,但仅限于同一模块内:

import (
    . "./testutils"  // 仅限测试代码,生产代码不推荐
)

对于外部依赖,始终使用完整的导入路径:

import (
    "github.com/gin-gonic/gin"
    "golang.org/x/sync/errgroup"
)
回到顶部