Go 在两个不同的结构上调用相同的函数

Go 在两个不同的结构上调用相同的函数,go,Go,我有两个函数,它们接受指向不同结构的不同指针,但结构具有相同的底层函数 func Save(db *sql.DB) error { db.Prepare(query) } func TxSave(tx *sql.Tx) error { tx.Prepare(query) } 当我将来需要扩展这个函数时,我不想对这两个函数都进行更改。在这种情况下,我怎样才能坚持住戈兰的干燥呢?哇,我想我爱上了围棋。实际上,我可以通过创建自己的接口来实现这一点 type Saver interface

我有两个函数,它们接受指向不同结构的不同指针,但结构具有相同的底层函数

func Save(db *sql.DB) error {
  db.Prepare(query)
}

func TxSave(tx *sql.Tx) error {
  tx.Prepare(query)
}

当我将来需要扩展这个函数时,我不想对这两个函数都进行更改。在这种情况下,我怎样才能坚持住戈兰的干燥呢?

哇,我想我爱上了围棋。实际上,我可以通过创建自己的接口来实现这一点

type Saver interface {
  Prepare(query string) (*sql.Stmt, error)
}

func Save(db *sql.DB) error {
  return GenericSave(db)
}

func TxSave(tx *sql.Tx) error {
  return GenericSave(tx)
}

func GenericSave(saver Saver) error {
  stmt := saver.Prepare(query)
  // Do rest with saver
}

哇,我想我爱上了围棋。实际上,我可以通过创建自己的接口来实现这一点

type Saver interface {
  Prepare(query string) (*sql.Stmt, error)
}

func Save(db *sql.DB) error {
  return GenericSave(db)
}

func TxSave(tx *sql.Tx) error {
  return GenericSave(tx)
}

func GenericSave(saver Saver) error {
  stmt := saver.Prepare(query)
  // Do rest with saver
}

创建一个接口,例如:

类型SQLRunner接口{
准备(查询字符串)(*sql.Stmt,错误)
PrepareContext(ctx context.context,查询字符串)(*sql.Stmt,错误)
查询(查询字符串,参数…接口{})(*行,错误)
QueryContext(ctx context.context,查询字符串,args…接口{})(*sql.Rows,错误)
//添加sql.Tx和sql.DB共享的尽可能多的方法
// ...
} 
然后创建一个使用该接口的方法:

func保存(s SQLRunner)错误{
s、 准备()
}
In-go接口实现是隐式的,因此您只需将*sql.Tx或*sql.DB传递给save函数:

保存(tx)
保存(db)

下面是一篇关于go中接口的好博文:

创建一个接口,例如:

类型SQLRunner接口{
准备(查询字符串)(*sql.Stmt,错误)
PrepareContext(ctx context.context,查询字符串)(*sql.Stmt,错误)
查询(查询字符串,参数…接口{})(*行,错误)
QueryContext(ctx context.context,查询字符串,args…接口{})(*sql.Rows,错误)
//添加sql.Tx和sql.DB共享的尽可能多的方法
// ...
} 
然后创建一个使用该接口的方法:

func保存(s SQLRunner)错误{
s、 准备()
}
In-go接口实现是隐式的,因此您只需将*sql.Tx或*sql.DB传递给save函数:

保存(tx)
保存(db)

这是一篇关于go中接口的好博文:

实际上,我在你面前也给出了同样的回答!我会接受这个正确答案,因为它有更多的细节。很高兴你发现了。Go中的隐式接口实现是一个非常有用的特性!事实上,我在你面前也做出了同样的回答!我会接受这个正确答案,因为它有更多的细节。很高兴你发现了。Go中的隐式接口实现是一个非常有用的特性!