【问题标题】:How does Go resolve seemingly same types?Go 如何解决看似相同的类型?
【发布时间】:2022-11-16 23:39:46
【问题描述】:

我有一个包含 2 列的 PostgreSQL 数据库:id (UUID)、company_url (varchar) 具有以下值:

2fc35af4-5f5c-445e-86c5-01d93513b8be | https://test.com
2bf31b75-d1f3-4a9c-a530-73b714816e9e | https://test2.com

下面是使用 Go 访问表的代码(为简单起见,省略了错误处理和凭据):

package main

import (
    "fmt"
    "database/sql"
    "github.com/google/uuid"
    _ "github.com/lib/pq"
)

func main() {
    connStr := "host= password= port= dbname= user="
    db, _ := sql.Open("postgres", connStr)
    rows, _ := db.Query("SELECT * FROM companies;")

    for rows.Next() {
        // var id [16]byte // not ok
        var id uuid.UUID // ok
        var companyURL string

        rows.Scan(&id, &companyURL)
        fmt.Println(id, companyURL)
    }
}

UUIDs 也有一个 Go 包。在它的源代码中,UUID 被简单地定义为

type UUID [16]byte

在上面的代码中ID是使用 uuid.UUID 键入的,我试图替换上面代码中的类型声明(用 not ok 注释掉),但它返回的不是正确的值,而是一个包含 16 个零的数组。 uuid.UUID 返回正确的 ID。

所以我的问题是,如果uuid.UUID[16]byte 是同一类型,为什么会出现这种行为? uuid 包中没有二进制文件,init() 函数也没有,Scan() 也没有进行任何隐式更改。

【问题讨论】:

  • rows.Scan 只能处理基本的内置类型,加上 time.Time 和其他几个,但除此之外,它不知道如何将数据库数据解码为自定义 Go 类型。为了能够使用自定义 Go 类型,你必须让该类型实现 sql.Scanner 接口,然后,rows.Scan,无论何时遇到这种类型的值,都会调用该接口并将其传递给原始字节以便该值可以“扫描自身”。 rows.Scan 也返回一个错误,如果你检查它,你会看到它在抱怨它不知道如何将数据解码为[16]byte

标签: sql postgresql go types uuid


【解决方案1】:

严格来说,它们不是同一种类型。不过他们有相同的underlying typeUUID的不同之处在于它implements接口sql.Scannerdriver.Valuer,所以它可以透明地与数据库一起使用。

【讨论】:

    猜你喜欢
    • 2019-09-11
    • 1970-01-01
    • 1970-01-01
    • 2021-06-01
    • 2014-04-19
    • 1970-01-01
    • 2017-04-15
    • 1970-01-01
    • 2020-12-29
    相关资源
    最近更新 更多