如何在Golang中使用Go接口实现类似Java的功能
如何在Golang中使用Go接口实现类似Java的功能 团队好,
我正在尝试用Go从数据库中读取数据。我有两个不同的结构体,而我的函数对于相同的代码返回这两个不同的结构体。
如何使其通用化。
type EventConfigDbDocs struct {
Docs []EventConfiguration `json:"docs"`
}
type EventDataDbDocs struct {
Docs []Event `json:"docs"`
}
func getEventConfig(selector string) []entities.EventConfiguration {
---
--
//Get the results from find.
eventResult := EventConfigDbDocs{}
–
return eventResult.Docs
}
请帮我解决这个问题。
谢谢
更多关于如何在Golang中使用Go接口实现类似Java的功能的实战教程也可以访问 https://www.itying.com/category-94-b0.html
7 回复
我正在尝试在同一个函数中实现两种不同的返回类型。

我还不明白你想要做什么。你能展示一下返回这两种类型中任意一种的函数吗?我在你最初的帖子中看到了 getEventConfig,但它只返回 []entities.EventConfiguration。你是说 getEventConfig 也能返回 []entities.Event 吗?如果是这样,我想看看代码是如何知道要返回什么类型的。
好的,我认为你需要三个函数:
loadQueryResults(当然,如果你有更好的名字,就用那个)getEventDatagetEventConfig
loadQueryResults 函数看起来应该和你当前的 getEventConfig 完全一样,但第14行传递给 Find 的 eventResults 应该变成该函数的一个参数:
func loadQueryResults(selector string, eventResult interface{}) {
// ...
// 注意:移除 &
err = db.Find(eventResult, ¶ms)
// ...
}
然后 getEventData 就变成:
finc getEventData(selector string) []entities.Event {
eventResult := struct {
Docs []entities.Event
}{}
loadQueryResults(selector, &eventResult)
return eventResult.Docs
}
然后 getEventConfig 就变成:
finc getEventConfig(selector string) []entities.EventConfiguration {
eventResult := struct {
Docs []entities.EventConfiguration
}{}
loadQueryResults(selector, &eventResult)
return eventResult.Docs
}
也许这正是你想要的:
package main
import (
"encoding/json"
"fmt"
)
type EventConfiguration struct{}
type Event struct{}
type DbDocs[TDbDoc any] struct {
Docs []TDbDoc `json:"docs"`
}
func loadFromCouch[TDbDoc any](eventResult *DbDocs[TDbDoc], selector string) []TDbDoc {
// 我不确定 `selector` 是否/在何处被使用。
db := connectcouchdb()
// 另外提一下,你不需要为了反序列化而特意创建JSON:
selectorObj := map[string]interface{}{
"_rev": map[string]interface{}{
"$eq": refId, // 不确定 `refId` 来自哪里
},
}
params := &couchdb.FindQueryParams{Selector: &selectorObj}
if err := db.Find(eventResult, params); err != nil {
fmt.Printf("ERROR: in find: %s", err)
}
if len(eventResult.Docs) != 0 {
fmt.Printf("Find Results Length: %v\n", len(eventResult.Docs))
fmt.Printf("Find docs: %v\n", eventResult.Docs)
} else {
fmt.Printf("Results: %v\n", len(eventResult.Docs))
}
return eventResult.Docs
}
func main() {
cfg := DbDocs[EventConfiguration]{}
cfgDocs := loadFromCouch(&cfg, "")
data := DbDocs[Event]{}
dataDocs := loadFromCouch(&data, "")
_, _ = cfgDocs, dataDocs
}
在Go中,可以使用接口和泛型(Go 1.18+)来实现类似Java的通用数据访问功能。以下是几种解决方案:
方案1:使用接口和类型断言
type DatabaseDocument interface {
GetDocs() interface{}
}
type EventConfigDbDocs struct {
Docs []EventConfiguration `json:"docs"`
}
func (e EventConfigDbDocs) GetDocs() interface{} {
return e.Docs
}
type EventDataDbDocs struct {
Docs []Event `json:"docs"`
}
func (e EventDataDbDocs) GetDocs() interface{} {
return e.Docs
}
func getFromDatabase[T any](selector string, dbDoc DatabaseDocument) []T {
// 模拟数据库查询
// ...
// 类型断言获取具体数据
if docs, ok := dbDoc.GetDocs().([]T); ok {
return docs
}
return nil
}
方案2:使用泛型(Go 1.18+)
type DbDocs[T any] struct {
Docs []T `json:"docs"`
}
func getFromDatabase[T any](selector string) []T {
var result DbDocs[T]
// 模拟数据库查询和JSON解码
// json.Unmarshal(data, &result)
return result.Docs
}
// 使用示例
func main() {
// 获取EventConfiguration
eventConfigs := getFromDatabase[EventConfiguration]("event_config")
// 获取Event
events := getFromDatabase[Event]("event_data")
}
方案3:结合接口和泛型的完整示例
package main
import (
"encoding/json"
"fmt"
)
type DatabaseQuery interface {
Query(selector string) ([]byte, error)
}
type EventConfiguration struct {
ID string `json:"id"`
Name string `json:"name"`
}
type Event struct {
ID string `json:"id"`
Timestamp int64 `json:"timestamp"`
}
type DbResponse[T any] struct {
Docs []T `json:"docs"`
}
func getGenericData[T any](db DatabaseQuery, selector string) ([]T, error) {
data, err := db.Query(selector)
if err != nil {
return nil, err
}
var response DbResponse[T]
if err := json.Unmarshal(data, &response); err != nil {
return nil, err
}
return response.Docs, nil
}
// 模拟数据库实现
type MockDatabase struct{}
func (m MockDatabase) Query(selector string) ([]byte, error) {
// 根据selector返回不同的模拟数据
if selector == "event_config" {
return json.Marshal(DbResponse[EventConfiguration]{
Docs: []EventConfiguration{
{ID: "1", Name: "Config1"},
{ID: "2", Name: "Config2"},
},
})
}
return json.Marshal(DbResponse[Event]{
Docs: []Event{
{ID: "1", Timestamp: 1234567890},
{ID: "2", Timestamp: 1234567891},
},
})
}
func main() {
db := MockDatabase{}
// 获取EventConfiguration
configs, _ := getGenericData[EventConfiguration](db, "event_config")
fmt.Printf("Configs: %+v\n", configs)
// 获取Event
events, _ := getGenericData[Event](db, "event_data")
fmt.Printf("Events: %+v\n", events)
}
方案4:使用反射(灵活性最高)
import (
"encoding/json"
"reflect"
)
func getData(selector string, result interface{}) error {
// 根据selector查询数据库
var data []byte
// ... 数据库查询逻辑
// 使用反射处理不同类型
v := reflect.ValueOf(result)
if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct {
return fmt.Errorf("result must be a pointer to struct")
}
// 创建临时结构体来解析
temp := struct {
Docs json.RawMessage `json:"docs"`
}{}
if err := json.Unmarshal(data, &temp); err != nil {
return err
}
// 解码到具体的Docs字段
docsField := v.Elem().FieldByName("Docs")
if !docsField.IsValid() {
return fmt.Errorf("struct has no Docs field")
}
return json.Unmarshal(temp.Docs, docsField.Addr().Interface())
}
// 使用示例
func exampleUsage() {
var configDocs EventConfigDbDocs
getData("event_config", &configDocs)
var eventDocs EventDataDbDocs
getData("event_data", &eventDocs)
}
推荐使用方案2的泛型方法,它提供了类型安全且代码简洁。如果项目使用Go 1.18以下版本,可以使用方案1的接口方法。


