GO 学习笔记之零 (三)常见问题处理集锦

1、Golang如何解决case-insensitive import collision问题

1.1 现象

1.2 解决方法

    该问题产生说明在所有go文件中引入包时,存在 ShipModel/Radar 和 ShipModel/radar 两种写法,需要统一。

     对于VSCODE工具,可以在 全局文件中搜索 ShipModel/Radar 查看 写法是不是一样,然后 进行统一,要么全部改成 ShipModel/Radar 或者全部改成  ShipModel/rada

2、panic: runtime error: invalid memory address or nil pointer dereference [recovered]

2.1 现象

      代码中 在 test.go 定义了全局变量(类型为自定义类型 struct),且通过init函数对该函数进行了初始化赋值。但是在利用 gin 框架 编写了 controller 层之后 使用  net/http/httptest 进行了单元测试,单元测试代码如下:

package test

import (
    "net/http"
    "net/http/httptest"
    "testing"

    "github.com/gin-gonic/gin"
    "github.com/stretchr/testify/assert"
    "test.com/pkg/server"

    "test.com/internal/controller"
)

func initEngine() *gin.Engine {
    engine := server.Register()
    for _, _method := range controller.RegisterFuncs {   //其中 _method 方法是 将 controller接口全部注册到 engine 引擎中,直接调用方法的时候,方法中会去执行全局变量对应类型的方法,但是此时提示 全局变量中的各个属性都是 nil。 造成单元测试执行失败
        _method(engine)
    }
    return engine
}

func TestHelloRoute(t *testing.T) {
    router := initEngine()

    w := httptest.NewRecorder()
    req, _ := http.NewRequest("GET", "/api/backup/hello", nil)
    router.ServeHTTP(w, req)

    assert.Equal(t, 200, w.Code)
    //assert.Equal(t, "pong", w.Body.String())
}

2.2 解决方法 

 经过百度查找资料 发现产生的原因是,通过 init() 函数初始化 全局变量时使用了 :=  导致的,需要更改成 = ,如果使用  := 表示还是局部变量

具体可参考资料: golang全局变量的一个坑,main中无法获取init初始化的变量 - 大墨垂杨 - 博客园      其中有详细说明

3、(VSCODE)单元测试调试sqlite数据库的连接性的时候,报错:failed to initialize database, got error Binary was compiled with 'CGO_ENABLED=0', go-sqlite3 requires cgo to work. This is a stub

3.1  现象

使用gorm 连接sqlite数据库,进行单元测试调试,出现以上报错

3.2 解决办法

在 Visual Studio Code (VSCode) 中运行 Go 单元测试时,可以通过以下几种方法来解决这个问题:

  1. 打开 VSCode 设置:

    • 按 Ctrl + , 打开设置。
    • 搜索 go.testEnvVars
  2. 添加环境变量:

    • 在 Go: Test Environment Variables 设置中,添加 CGO_ENABLED=1

    例如:

"go.testEnvVars": {
  "CGO_ENABLED": "1"
}

3.3 进一步遇到的问题

3.3.1 解决办法

1)安装 最新版本的 mingw64 (Releases · niXman/mingw-builds-binaries

  •   打开github,下载最新版本的  7z 格式的成果物

 

  • 解压到 对应目录下,将 bin 加入到系统环境变量 path下
  • 配置环境变量:
    • 安装完成后,需要将 MinGW 的 bin 目录添加到系统的 PATH 环境变量中。
    • 打开“控制面板” -> “系统和安全” -> “系统” -> “高级系统设置”。
    • 点击“环境变量”。
    • 在“系统变量”部分,找到 Path 变量,点击“编辑”。
    • 添加 MinGW 的 bin 目录路径,例如 C:\MinGW\bin
    • 点击“确定”保存设置。
  • 验证安装:
    • 打开命令提示符(按 Win + R,输入 cmd,按回车)。
    • 输入 gcc --version,如果安装成功,会显示 GCC 的版本信息。

通过以上方式可以正确跑验证sqlite 连接的 单元测试用例了。

 4、failed to auto migrate: unsupported data type: &[]

4.1 现象

package main

import (
    "log"
    "gorm.io/gorm"
    "gorm.io/driver/sqlite"
)

// 定义一个结构体,表示表中的数据
type User struct {
    ID   uint   `gorm:"primaryKey"`
    Name string `gorm:"not null"`
    Age  int    `gorm:"not null"`
}

func main() {
    // 连接到 SQLite 数据库(如果数据库不存在,则会创建一个新的数据库)
    db, err := gorm.Open(sqlite.Open("example.db"), &gorm.Config{})
    if err != nil {
        log.Fatalf("failed to connect database: %v", err)
    }

    // 自动迁移表结构
    err = db.AutoMigrate(&User{})
    if err != nil {
        log.Fatalf("failed to auto migrate: %v", err)
    }

    log.Println("Database and table created successfully!")
}

在上述代码中通过 db.AutoMigrate(&User{}) 进行表自动迁移,也就是在example.db 中可以自动创建这个表,但是 有的表结构定义较负责,用到切片类型,测试,会报错  unsupported data type: &[]

4.2 解决办法

1)嵌套的切片或数组:GORM 不支持嵌套的切片或数组类型。

2)复杂的结构体:GORM 不支持嵌套的结构体类型。

3)自定义数据类型:GORM 不支持自定义的数据类型,除非你实现了 Scanner 和 Valuer 接口。

解决方法

  建议使用: 实现了 Scanner 和 Valuer 接口 解决该问题

package main

import (
    "database/sql/driver"
    "errors"
    "strings"
    "gorm.io/gorm"
    "gorm.io/driver/sqlite"
)

type User struct {
    ID        uint
    Name      string
    Tags      TagList `gorm:"type:text"`
}

type TagList []string

//--------------------------- func (t TagList) Value() (driver.Value, error) { return strings.Join(t, ","), nil } func (t *TagList) Scan(value interface{}) error { if value == nil { *t = TagList{} return nil } str, ok := value.(string) if !ok { return errors.New("type assertion to string failed") } *t = strings.Split(str, ",") return nil }
//----------
//或者直接用json进行转换
func (c *TagList) Scan(value interface{}) error {
    if value == nil {
        return nil
    }
    str, ok := value.(string)
    if !ok {
        return fmt.Errorf("cannot covert %T into string", value)
    }

    return json.Unmarshal([]byte(str), c)
}

func (c TagList) Value() (driver.Value, error) {
    jsonBytes, err := json.Marshal(c)
    if err != nil {
        return nil, err
    }
    return string(jsonBytes), nil
}
func main() {
    db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
    if err != nil {
        panic("failed to connect database")
    }

    db.AutoMigrate(&User{})

    // 示例数据
    user := User{
        Name:  "John Doe",
        Tags:  TagList{"tag1", "tag2"},
    }

    db.Create(&user)

    var result User
    db.First(&result, user.ID)

    println(result.Name)
    println(strings.Join(result.Tags, ","))
}

 5、VSCODE 运行go程序时 报go版本不匹配

5.1 现象

     工程已经配置了 lanch.json文件,点击调试中该文件对应的 调试运行按钮,出现下图所示:

 Snipaste_2025-08-12_11-04-11

5.2 解决方案

依赖库要求 go 版本是 1.23.4版本,因此需要升级工具集成的go版本,直接从官网下载匹配版本进行安装即可

6、VSCODE 运行go程序时报 3221225781

6.1 现象  

运行报错,这个表示 程序运行时缺少依赖的dll库

 image

6.2 解决方案

1)将要用的dll 文件放到 main.go 所在目录

2) 配置 lanuch.json 工作目录

{
    // 使用 IntelliSense 了解相关属性。 
    // 悬停以查看现有属性的描述。
    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "opsmgr",
            "type": "go",
            "request": "launch",
            "mode": "auto",
            "program": "E:\\gowork\\src\\git\\xxx\\src\\test.com\\core\\start\\main.go",
            "cwd": "E:\\gowork\\src\\git\\xxx\\src\\test.com\\core\\start",             // 工作目录
            //  "env": {
            //      "PATH": "${env:PATH};E:\\gowork\\src\\git\\xxx\\src\\test.com\\base\\identify\\win64\\Identify.dll", // 添加DLL目录     ---- 这样配置无效,不知道为啥
            //   },
              "trace": "verbose",
            "showLog": true
        }
    ]
}

 

posted @ 2024-12-27 16:09  夏之夜  阅读(230)  评论(0)    收藏  举报