如何使用interface {}作为灵活的函数参数和返回类型?

时间:2017-09-20 19:55:36

标签: function go parameters casting

我是Go的初学者,我现在正在编写一个可以调用API的函数。该函数接收URL的一部分(/user/account等)和结构,以将返回的json转换为(例如,结构UserAccount)参数。

所以我现在有了这个:

func (self *RestClient) request(action string, return_type interface{}) interface{} {
    res, _ := goreq.Request{Uri:self.url + action}.Do()
    var item return_type
    res.Body.FromJsonTo(&item)
    return item
}

我尝试使用(Index是返回类型的结构)来调用此函数:

self.request("/api/v1/public/index", Index)

但这不起作用。我收到以下错误:

return_type is not a type
type Index is not an expression

我想我明白为什么会这样。我想我必须以某种方式找出return_type的类型,然后将return_type转换为该类型,然后再将其用作item的类型。我不知道怎么回事。 关于第二个错误,我不知道。我甚至不理解它的含义。

有人可以帮帮我吗?我怎样才能做到这一点?或者这应该以完全不同的方式完成吗?欢迎所有提示!

2 个答案:

答案 0 :(得分:4)

基于此代码的一些提示:

  • 不要使用自己使用有意义的标识符
  • 不要使用接口{}来避免处理类型系统
  • 不要使用反射
  • 不要忽略返回的错误(来自FromJsonTo或goreq.Request)
  • 不要使用像goreq这样的库,除非你确定你需要它(你没有) - 你正在提取你不需要的lots代码,它教会你不好的习惯,比如尝试使用空接口和反射来解决简单问题。

看一下FromJsonTo的定义 - 如果你浏览一下这个库,你会发现它不会为你节省很多精力并增加了很多复杂性。如果没有库,你可以这样做:

func (c *RestClient) Request(action string, resource interface{}) error {
    res, err := http.Get(c.url + action)
    if err != nil {
        return err
    }
    defer res.Body.Close()
    return json.NewDecoder(res.Body).Decode(resource)
}

或者使用接口并将解码移动到资源(可以嵌入默认解码器):

type Decoder interface {
    Decode(r io.Reader) error
}

// RequestDecode fetches a request and feeds it to the decoder
func (c *RestClient) RequestDecode(action string, resource Decoder) error {
    res, err := http.Get(c.url + action)
    if err != nil {
        return err
    }
    defer res.Body.Close()
    return resource.Decode(res.Body)
}

答案 1 :(得分:0)

我首先要说你应该经常检查任何可能返回错误的函数的错误。

您看到的错误是因为您尝试将变量item声明为类型return_type,这是函数参数的名称。

另一个错误来自Index是一个类型声明,而不是Index类型的具体值。

我同意Volker的评论但是把它放在代码中,你可以使用这样的东西:

func (self *RestClient) request(action string, return_type interface{}) {
    res, err := goreq.Request{Uri:self.url + action}.Do()
    if err != nil {
        // Do something with error here.
    }
    res.Body.FromJsonTo(return_type)
}

var index Index
rest_client.request("/some/path", &index)

这允许灵活性但如果您忘记将指针传递给值return_type,则可能导致奇怪的情况。