为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
吃鸡游戏 2022-07-25 11:13:01
我正在尝试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 apio := 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 中以使其在外部可用?
查看完整描述

2 回答

?
临摹微笑

TA贡献1982条经验 获得超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 result

cc.requestAPI(url, &dst)


查看完整回答
反对 回复 2022-07-25
?
蝴蝶刀刀

TA贡献1801条经验 获得超8个赞

在某些假设下,例如您将 json 数据存储在下面的缓存中,我将尝试这样做。错误未处理。


package main


import (

    "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 main


import (

    "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)

}


查看完整回答
反对 回复 2022-07-25
  • 2 回答
  • 0 关注
  • 89 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信