通过将结构体指针作为 interface{} 类型参数传入,可复用 mongodb 查询函数处理任意结构体,无需反射或类型断言,mongo 驱动原生支持该方式。
在 Go 中实现数据库查询逻辑的复用,关键在于理解 interface{} 的行为本质:它不仅是一个“空接口”,更是一个能完整承载任意具体类型值(包括指针)的容器。当您将 &user(如 *User)或 &post(如 *Post)传递给接受 interface{} 参数的函数时,Go 运行时会自动保留其底层类型和内存地址信息——这正是 MongoDB 官方驱动(如 gopkg.in/mgo.v2 或 go.mongodb.org/mongo-driver/mongo 的早期兼容层)中 One() 方法能够正确反序列化并填充目标结构体的前提。
因此,最简洁、高效且符合 Go 惯例的解决方案是直接使用 interface{} 作为接收结构体指针的参数类型,并确保调用时传入的是指向具体结构体的指针:
func findEntry(db, table string, entry interface{}, finder bson.M) error {
c := mongoSession.DB(db).C(table)
return c.Find(finder).One(entry)
}✅ 调用示例(支持任意结构体):
// 查询 User
var user User
err := findEntry("mydb", "users", &user, bson.M{"email": "alice@example.com"})
// 查询 Post
var post Post
err := findEntry("mydb", "posts", &post, bson.M{"slug": "hello-world"})
// 查询 Product
var product Product
err := findEntry("mydb", "products", &product, bson.M{"in_stock": true})⚠️ 注意事项:
该方案零依赖反射、零运行时类型转换开销,完全遵循 Go 的接口设计哲学:“接受接口,返回具体类型;让调用者决定实现”。它不是权宜之计,而是 Go 生态中操作序列化数据的标准实践。