英文:
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"
}
}
注意:
pgx
和pgconn
包在同一个项目中,所以它们不会返回具有相同名称的不同版本的类型。换句话说,我的 go.mod 文件中只有一个导入。- 返回的值不是 nil。
- 调试器显示该类型是
*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:
- The
pgx
andpgconn
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. - The returned value is not nil.
- A debugger reveals that the type is a
*pgconn.PgError
.
答案1
得分: 1
正如@HymnsForDisco在评论中正确指出的那样,github.com/jackc/pgconn
和github.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/rand
和crypto/rand
,它们都叫做rand
。这是*pgconn.PgError
和*pgconn.PgError
不同的第一个提示:它们来自不同的导入路径。
当Go模块进行重大修改时,它们应该更改其导入路径。这是为了保持与导入路径相关的向后兼容性。请注意,通常是通过更新go.mod
文件中的module
声明来完成,而不是实际将代码移动到子目录中。例如,查看这个提交,其中pgx
从v4
升级到v5
。这是第二个提示:pgx
项目的代码可以通过多个导入路径访问(由于多个主要版本)。
有了这个背景知识,我使用git标签查看了最新的v4.x.x
发布版本的存储库。我注意到奇怪的是,在v4
中不存在pgconn
包。这似乎排除了github.com/jackc/pgx/v4/pgconn
与github.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"
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论