如何在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 回复

请帮忙

更多关于如何在Golang中使用Go接口实现类似Java的功能的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我正在尝试在同一个函数中实现两种不同的返回类型。

image

我还不明白你想要做什么。你能展示一下返回这两种类型中任意一种的函数吗?我在你最初的帖子中看到了 getEventConfig,但它只返回 []entities.EventConfiguration。你是说 getEventConfig 也能返回 []entities.Event 吗?如果是这样,我想看看代码是如何知道要返回什么类型的。

非常感谢!!

type Dbdocs interface {
GetDbDocs() interface{}
}
type EventConfigDbDocs struct {
Docs []EventConfiguration `json:"docs"`
}
type EventDataDbDocs struct {
Docs []Event `json:"docs"`
}
func (econfigdocs EventConfiguration) GetDbDocs() interface{} {
return EventConfigDbDocs{}
}
func (edatadocs EventDataDbDocs) GetDbDocs() interface{} {
return EventDataDbDocs{}
}

在 Go 语言中,是否可能创建一个具有多个返回值的接口?如果可以,我们该如何实现?

好的,我认为你需要三个函数:

  1. loadQueryResults(当然,如果你有更好的名字,就用那个)
  2. getEventData
  3. getEventConfig

loadQueryResults 函数看起来应该和你当前的 getEventConfig 完全一样,但第14行传递给 FindeventResults 应该变成该函数的一个参数:

func loadQueryResults(selector string, eventResult interface{}) {
    // ...
    // 注意:移除 &
   err = db.Find(eventResult, &params)
    // ...
}

然后 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的接口方法。

回到顶部