【问题标题】:Slice of pointers to interface for MySQL queries abstractions指向 MySQL 查询抽象接口的指针切片
【发布时间】:2018-05-30 13:30:40
【问题描述】:

我试图抽象出我对 MySQL 数据库的使用,但我遇到了一个错误。

有一个对象我会举个例子:

package models

// Product : The Product's model
type Product struct {
    ID         int
    Name       string
    Price      int
    PictureURL string
}

我将尝试在我的数据库中检索产品id = 1。为此,假设我已经与我的数据库建立了连接,该连接由下一个变量表示:

var databaseMySQL *sql.DB

为了查询我的数据库,我使用了这个函数:

// QueryMySQL query our MySQL database
func QueryMySQL(sqlquery model.SQLQuery) model.Status {

    // prepare the query
    stmtOut, err := databaseMySQL.Prepare(sqlquery.Query)
    if err != nil {
        return model.Status{Code: http.StatusInternalServerError, Error: err}
    }
    defer stmtOut.Close()

    // Run the query
    err = stmtOut.QueryRow(sqlquery.Args).Scan(sqlquery.Dest)
    if err != nil {
        return model.Status{Code: http.StatusInternalServerError, Error: err}
    } else {
        return model.Status{Code: http.StatusOK, Error: nil}
    }
}

这里使用的 2 个模型是 SQLQueryStatus

package models

type SQLQuery struct {
    Query string
    Args  []interface{}
    Dest  []*interface{}
}

Status 基本上只包含一个error 和一个int

所以,既然Scan()作为下面的原型Scan func(dest ...interface{}) error,我可以传递一个[]*interface{}作为参数。

如果我是对的,那么我应该能够让我的 Dest 的元素由T 类型元素填充,然后将它们转换/转换为我需要的类型?

func GetProductByID(ID int) (model.Product, model.Status) {

    // "SELECT ID, Name, Price, PictureURL FROM Products WHERE ID = ?"
    var _product model.Product

    // HERE IS THE PROBLEM
    var dest []*interface{}
    append(dest, &_product.Name)
    append(dest, &_product.Price)
    append(dest, &_product.PictureURL)
    // HERE IS THE PROBLEM

    status := QueryMySQL(model.SQLQuery{
        Query: "SELECT Name, Price, PictureURL FROM Products WHERE ID = ?",
        Args:  []interface{}{ID},
        Dest:  dest})

    return _product, model.Status{Code: http.StatusOK, Error: nil}
}

PS:这个功能只是一个基本的测试,试试我的逻辑

但是,我收到一个错误:

不能在追加中使用 &_product.Name (type *string) 作为 type *interface {}: *interface {} 是指向接口的指针,而不是接口

对我来说,有两个错误:

  • cannot use &_product.Name (type *string) as type *interface {}
  • *interface {} is pointer to interface, not interface

首先,为什么我不能使用接口来存储我的字符串?

其次,既然我在字符串上传递一个指针,那么interface{} 是怎么回事?它应该是 *interface{},不是吗?


正确的代码,感谢 David Budworth 的回答

除了给定的代码之外,您还可以像我一样通过在切片变量名称后添加... 将切片作为可变参数传递

mysqlproduct.go

// GetProductByID returns a Product based on a given ID
func GetProductByID(ID int) (model.Product, model.Status) {

    _product := model.Product{
        ID: ID}

    status := QueryMySQL(&model.SQLQuery{
        Query: "SELECT Name, Price, PictureURL FROM Products WHERE ID = ?",
        Args:  []interface{}{_product.ID},
        Dest:  []interface{}{&_product.Name, &_product.Price, &_product.PictureURL}})

    if status.Code != http.StatusOK {
        return _product, status
    }

    return _product, model.Status{Code: http.StatusOK, Error: ""}
}

mysql.go

// QueryMySQL query our MySQL database
func QueryMySQL(sqlquery *model.SQLQuery) model.Status {

    stmtOut, err := databaseMySQL.Prepare(sqlquery.Query)
    if err != nil {
        return model.Status{Code: http.StatusInternalServerError, Error: err.Error()}
    }
    defer stmtOut.Close()

    // Run the query
    err = stmtOut.QueryRow(sqlquery.Args...).Scan(sqlquery.Dest...)
    if err != nil {
        return model.Status{Code: http.StatusInternalServerError, Error: err.Error()}
    }
    defer stmtOut.Close()

    return model.Status{Code: http.StatusOK, Error: ""}
}

【问题讨论】:

标签: mysql pointers go interface slice


【解决方案1】:

接口可以保存指针。很少有理由创建一个指向接口的指针。

如果您将类型更改为 []interface{},它应该可以工作。

如果您真的想要指向接口的指针,出于某种原因,您必须首先将字段存储在接口中,然后获取指向该接口的指针。

即:

var i interface{} = &_product.Name
append(dest, &i)

【讨论】:

  • 这很有趣,我会尝试一下。我是一名 C 开发人员,所以我理解指针,但我将接口 {} 视为 void *,并且由于该函数将结果存储到可变参数指针中,我想知道是否可以使其通用,你明白吗?
  • interface{} 更像struct { ANY val, Type t },但它可以保存一个值或指向一个值的指针。因此,如果您将指针存储在普通的旧接口中,则接收器(sql 包)将能够在该指针处存储内容。而且,由于接口包含类型,接收者甚至可以分配内存来存储值。因此您可以传递一个空指针(尽管在您的示例中,obj 已被分配)
  • Hoooo 好的,这很有意义 :) 谢谢你的回答 :) 我的代码还没有返回数据(产品刚刚初始化但没有填充数据)但是你回答了主要问题所以谢谢10000 次 :)
猜你喜欢
  • 2021-12-09
  • 2015-05-01
  • 2017-07-04
  • 2016-07-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-03
  • 2014-10-09
相关资源
最近更新 更多