1 回答

TA貢獻(xiàn)1865條經(jīng)驗(yàn) 獲得超7個贊
為了消除掃描結(jié)構(gòu)所需步驟的重復(fù),*sql.Rows您可以引入兩個接口。一個描述*sql.Rows和的已經(jīng)實(shí)現(xiàn)的行為*sql.Row。
// This interface is already implemented by *sql.Rows and *sql.Row.
type Row interface {
Scan(...interface{}) error
}
另一個抽象出行的實(shí)際掃描步驟。
// have your entity types implement this one
type RowScanner interface {
ScanRow(Row) error
}
RowScanner 接口的示例實(shí)現(xiàn)如下所示:
type User struct {
Id uint
Username string
// ...
}
// Implements RowScanner
func (u *User) ScanRow(r Row) error {
return r.Scan(
&u.Id,
&u.Username,
// ...
)
}
type UserList struct {
Items []*User
}
// Implements RowScanner
func (list *UserList) ScanRow(r Row) error {
u := new(User)
if err := u.ScanRow(r); err != nil {
return err
}
list.Items = append(list.Items, u)
return nil
}
使用這些接口,您現(xiàn)在可以為所有通過使用這兩個函數(shù)實(shí)現(xiàn) RowScanner 接口的類型干燥行掃描代碼。
func queryRows(query string, rs RowScanner, params ...interface{}) error {
rows, err := db.Query(query, params...)
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
if err := rs.ScanRow(rows); err != nil {
return err
}
}
return rows.Err()
}
func queryRow(query string, rs RowScanner, params ...interface{}) error {
return rs.ScanRow(db.QueryRow(query, params...))
}
// example
ulist := new(UserList)
if err := queryRows(queryString, ulist, arg1, arg2); err != nil {
panic(err)
}
// or
u := new(User)
if err := queryRow(queryString, u, arg1, arg2); err != nil {
panic(err)
}
如果您有想要掃描的復(fù)合類型,但又想避免重復(fù)枚舉其元素的字段,那么您可以引入一種返回類型字段的方法,并在需要的地方重用該方法。例如:
func (u *User) ScannableFields() []interface{} {
return []interface{}{
&u.Id,
&u.Username,
// ...
}
}
func (u *User) ScanRow(r Row) error {
return r.Scan(u.ScannableFields()...)
}
// your other entity type
type Site struct {
Id uint
Name string
// ...
}
func (s *Site) ScannableFields() []interface{} {
return []interface{}{
&p.Id,
&p.Name,
// ...
}
}
// Implements RowScanner
func (s *Site) ScanRow(r Row) error {
return r.Scan(s.ScannableFields()...)
}
// your composite
type UserWithSite struct {
User *User
Site *Site
}
// Implements RowScanner
func (u *UserWithSite) ScanRow(r Row) error {
u.User = new(User)
u.Site = new(Site)
fields := append(u.User.ScannableFields(), u.Site.ScannableFields()...)
return r.Scan(fields...)
}
// retrieve from db
u := new(UserWithSite)
if err := queryRow(queryString, u, arg1, arg2); err != nil {
panic(err)
}
- 1 回答
- 0 關(guān)注
- 107 瀏覽
添加回答
舉報