Go类型转换失败,尽管类型相同。

huangapple go评论105阅读模式
英文:

Go type cast fails despite the type being the same

问题

我正在使用 jackc/pgx 驱动程序与 GORM 库一起与 PostgreSQL 数据库进行交互。

我有一个情况,需要检查 PostgreSQL 错误代码并以不同的方式处理特定的错误类型。当使用 pgx 驱动程序时,GORM 方法返回一个 *pgconn.PgError 类型作为 error,其中包含具体的错误代码字段。

为了访问该字段,我必须将 error 强制转换为 *pgconn.PgError,但出于某种原因,这个转换失败了:

res := tx.Take(&f, "id = ?", id)
if res.Error != nil {
    if pqErr, ok := res.Error.(*pgconn.PgError); ok {
        // 这里无法执行
    } else {
        fmt.Printf("Error type: %T\n", res.Error)
        // 输出: "Error type: *pgconn.PgError"
    }
}

注意:

  1. pgxpgconn 包在同一个项目中,所以它们不会返回具有相同名称的不同版本的类型。换句话说,我的 go.mod 文件中只有一个导入。
  2. 返回的值不是 nil。
  3. 调试器显示该类型是 *pgconn.PgError
英文:

I am using the jackc/pgx driver alongside the GORM library to interface with a PostgreSQL database.

I have an instance where I have to check the PostgreSQL error code and handle a certain error type differently. When using the pgx driver, the GORM methods return a *pgconn.PgError type as the error, which contains a field with the specific error code.

In order to access that field, I must cast the error to a *pgconn.PgError, but for some reason this is failing:

res := tx.Take(&f, "id = ?", id)
if res.Error != nil {
    if pqErr, ok := res.Error.(*pgconn.PgError); ok {
        // does not reach here
    } else {
        fmt.Printf("Error type: %T\n", res.Error)
        // Output: "Error type: *pgconn.PgError"
    }
}

Notes:

  1. The pgx and pgconn packages are inside the same project, so it's not the case that they are returning different versions of a type with the same name. In other words, I only have one import in my go.mod.
  2. The returned value is not nil.
  3. A debugger reveals that the type is a *pgconn.PgError.

答案1

得分: 1

正如@HymnsForDisco在评论中正确指出的那样,github.com/jackc/pgconngithub.com/jackc/pgx/pgconn都存在。结果发现返回的错误来自前者,而我在代码中导入的是后者。

为了确认,我添加了以下代码:

fmt.Println("Error path: ", reflect.TypeOf(res.Error).Elem().PkgPath())
// 输出: "Error path:  github.com/jackc/pgconn"

将我的导入更改为"github.com/jackc/pgconn"解决了这个问题。

英文:

As @HymnsForDisco correctly pointed out in the comments, both github.com/jackc/pgconn and github.com/jackc/pgx/pgconn exist. It turns out that the returned error was from the former, whereas I was importing the latter in my code.

To confirm, I added the following line:

fmt.Println("Error path: ", reflect.TypeOf(res.Error).Elem().PkgPath())
// Output: "Error path:  github.com/jackc/pgconn"

Changing my import to "github.com/jackc/pgconn" resolved the issue.

答案2

得分: 1

你已经解决了自己的问题,但是这里有一些可能有帮助的背景信息,以及我是如何找到问题源的。

在同一个程序中可以存在同名的包,只要它们有不同的导入路径。例如,标准库中有math/randcrypto/rand,它们都叫做rand。这是*pgconn.PgError*pgconn.PgError不同的第一个提示:它们来自不同的导入路径。

当Go模块进行重大修改时,它们应该更改其导入路径。这是为了保持与导入路径相关的向后兼容性。请注意,通常是通过更新go.mod文件中的module声明来完成,而不是实际将代码移动到子目录中。例如,查看这个提交,其中pgxv4升级到v5。这是第二个提示:pgx项目的代码可以通过多个导入路径访问(由于多个主要版本)。

有了这个背景知识,我使用git标签查看了最新的v4.x.x发布版本的存储库。我注意到奇怪的是,在v4中不存在pgconn包。这似乎排除了github.com/jackc/pgx/v4/pgconngithub.com/jackc/pgx/v5/pgconn冲突的可能性。然后,我在Google上搜索了"pgconn",找到了github.com/jackc/pgconn存储库,在其中的README中看到:
> 这个版本与pgx v4一起使用。在pgx v5中,它是https://github.com/jackc/pgx存储库的一部分。

根据你提供的其他信息,你的错误可能是使用了导入路径"github.com/jackc/pgx/pgconn"。如pgx的示例代码所示,你应该使用的基本模块的导入路径是"github.com/jackc/pgx/v5",其中的包也可以类似地指定,例如"github.com/jackc/pgx/v5/pgconn"

英文:

You've solved your own issue, but here's some perhaps helpful background, and how I found the source.

Packages of the same name can exist in the same program, so long as they have different import paths. For example, the standard library has both math/rand and crypto/rand, each called rand. This is the first hint of how *pgconn.PgError and *pgconn.PgError are not the same: they come from different import paths.

When modules in Go make major revisions, they are supposed to change their import path. This is to preserve backwards compatibility with respect to import paths. Note that this is usually done by updating the module declaration in the go.mod file, rather than actually moving the code into a sub-directory. For example, see this commit where pgx was bumped from v4 to v5. This is the second hint: code from the pgx project is available under multiple import paths (due to the multiple major versions).

With this background in mind, I used the git tags to view the repository at the latest v4.x.x release. I noticed that oddly, the pgconn package did not exist in v4. This seemed to rule out the idea of a github.com/jackc/pgx/v4/pgconn vs github.com/jackc/pgx/v5/pgconn conflict. I then Google searched for "pgconn" and found the github.com/jackc/pgconn repository, where I saw in the README:
> This version is used with pgx v4. In pgx v5 it is part of the https://github.com/jackc/pgx repository.

From the other information you've given, your mistake may have been using the import path "github.com/jackc/pgx/pgconn". As shown in the example code for pgx, the current import path you should be using for the base module is "github.com/jackc/pgx/v5", and packages within it would be specified similarly, e.g., "github.com/jackc/pgx/v5/pgconn".

huangapple
  • 本文由 发表于 2023年2月15日 09:35:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/75454761.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定