尝试使用空接口参数返回数据时出错

我正在尝试interface{}通过添加缓存来编写一个使用参数返回数据的函数的包装。


我的问题是,一旦我有一个有效的interface{}我不知道如何分配它以在参数中返回。包装的调用(github.Client) .Do在github API 客户端中,当我尝试使用go-cache添加缓存时,问题就来了


这有点我的功能


func (c *cachedClient) requestAPI(url string, v interface{}) error {

    x, found := c.cache.Get(url)

    if found {                        // Found in cache code

        log.Printf("cached: %v", x)

        v = x // HERE: this do not work. x contains a valid copy of what I want but how do I store it in v?

        return nil

    }

    req, _ := c.githubClient.NewRequest("GET", url, nil)    // not found I cache, request it

    res, err := c.githubClient.Do(*c.context, req, v)

    if err != nil {

        return err

    }

    if res.StatusCode != 200 {

        return fmt.Errorf("Error Getting %v: %v", url, res.Status)

    }

    c.cache.Add(url, v, cache.DefaultExpiration)   // store in cache

    return nil    // once here v works as expected and contain a valid item

}

当我尝试像这样使用它时必须返回缓存值时它会失败:


// Some init code c is a cachedClient 

i := new(github.Issue)


c.requestAPI(anAPIValidURLforAnIssue, i)

log.Printf("%+v", i)    // var i correctly contains an issue from the github api


o := new(github.Issue)

c.requestAPI(anAPIValidURLforAnIssue, o)

log.Printf("%+v", o)  // var o should have been get from the cache but here is empty

所以基本上我的问题是,当我正确恢复缓存项目时它很好,但我不能将它存储在用于存储它的参数中。我不能使用子类,因为我正在包装的调用interface{}已经使用了。而且我不能移动它来返回值,因为你不能返回一个通用接口。如何使interface{} x存储在 v 中以使其在外部可用?


吃鸡游戏
浏览 92回答 2
2回答

临摹微笑

要归档您想要的内容,您需要使用一些反射魔法。请尝试v = x用下一个代码段替换:reflect.ValueOf(v).Elem().Set(reflect.ValueOf(x).Elem())来自 OP 的注释:我必须添加最后一个.Elem()才能完成这项工作。注意:在调用该requestAPI方法时,您应该使用指向该值的指针:假设缓存的值是 type int。然后你应该requestAPI像这样打电话:var dst int // destination of the cached value or a newly retrieved resultcc.requestAPI(url, &dst)

蝴蝶刀刀

在某些假设下,例如您将 json 数据存储在下面的缓存中,我将尝试这样做。错误未处理。package mainimport (    "encoding/json"    "fmt")type Data struct {    Name string}func main() {    var d Data    requestAPI(&d)    fmt.Println(d)}func requestAPI(v interface{}) {    var cache_res interface{} = []byte("{\"Name\":\"CCC\"}")    //assume you got cache_res from cache    x, _ := cache_res.([]byte)    _ = json.Unmarshal(x, &v)}其实上面githubClient.Do也是在做的。它检查 v 是否满足io.Writer接口,如果是,则将数据写入 v。如果不是,则将 json 解组到 v 中,如上所示。所以同样可以从缓存中完成。在这里查看: https ://github.com/google/go-github/blob/v32.1.0/github/github.go#L586如果缓存对象是特定的,则可以使用以下内容。您不处理空接口{},因为您应该能够将特定类型传递给c.githubClient.Doas v。由于它使用 json 包,它将检测类型信息并相应地将值填充到其中。假设您存储type Data struct在下面的代码中,消除了其他细节,例如条件检查是否缓存和错误处理package mainimport (    "fmt")type Data struct {    Name string}func main() {    var d Data    requestAPI(&d)    fmt.Println(d)}func requestAPI(v *Data) {    var cache_res interface{} = Data{"CCC"}    //assume you got cache_res from cache    x, _ := cache_res.(Data)    *v = x    //in case you did not find it in cache then githubClient.Do should unmarshal    //contents of response body into v *Data if Data fields match that of json    //res, err := c.githubClient.Do(*c.context, req, v)}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go