尝试使用空接口参数返回数据时出错
Error trying to use an empty interface parameter for returning data
我正在尝试通过添加缓存来编写一个将 interface{}
参数用于 return 数据的函数。
我的问题是,一旦我有了一个有效的 interface{}
,我就不知道如何在参数中将其指定为 returned。封装的调用是 (github.Client) .Do
in github API client and the problem hit me when I tried to add caching with 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
}
当我尝试像这样使用它时必须 return 缓存值时失败:
// 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{}
。而且我不能将它移动到 return 值,因为你不能 return 通用接口。如何将 interface{} x
存储在 v 中以使其在外部可用?
根据某些假设,比如您正在将 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
如果缓存对象是特定的,则可以使用以下内容。您不处理空接口{},因为您应该能够将您的特定类型作为 v 传递给 c.githubClient.Do
。由于它使用 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)
}
要存档您需要的内容,您需要使用一些反射魔法。
请尝试用下一个代码片段替换 v = x
:
reflect.ValueOf(v).Elem().Set(reflect.ValueOf(x).Elem())
OP 的注释:我必须添加最后一个 .Elem()
才能完成这项工作。
注意:在 requestAPI
方法的调用中,您应该使用指向该值的指针:
假设缓存值的类型为 int
。那么你应该像这样调用 requestAPI
:
var dst int // destination of the cached value or a newly retrieved result
cc.requestAPI(url, &dst)
我正在尝试通过添加缓存来编写一个将 interface{}
参数用于 return 数据的函数。
我的问题是,一旦我有了一个有效的 interface{}
,我就不知道如何在参数中将其指定为 returned。封装的调用是 (github.Client) .Do
in github API client and the problem hit me when I tried to add caching with 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
}
当我尝试像这样使用它时必须 return 缓存值时失败:
// 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{}
。而且我不能将它移动到 return 值,因为你不能 return 通用接口。如何将 interface{} x
存储在 v 中以使其在外部可用?
根据某些假设,比如您正在将 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
如果缓存对象是特定的,则可以使用以下内容。您不处理空接口{},因为您应该能够将您的特定类型作为 v 传递给 c.githubClient.Do
。由于它使用 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)
}
要存档您需要的内容,您需要使用一些反射魔法。
请尝试用下一个代码片段替换 v = x
:
reflect.ValueOf(v).Elem().Set(reflect.ValueOf(x).Elem())
OP 的注释:我必须添加最后一个 .Elem()
才能完成这项工作。
注意:在 requestAPI
方法的调用中,您应该使用指向该值的指针:
假设缓存值的类型为 int
。那么你应该像这样调用 requestAPI
:
var dst int // destination of the cached value or a newly retrieved result
cc.requestAPI(url, &dst)