Go接口方法的使用

huangapple go评论90阅读模式
英文:

Go interface method usage

问题

我使用Martini库编写了一个非常简单的Go应用程序。在组合一个简单的REST API示例时,当发生错误时,我想将JSON数据呈现给用户,例如:

{
    error: "Document Not Found",
    code: 404
}

我使用以下代码返回一个Martini可以将其呈现为JSON的映射。

package ErrorResponces

import "net/http"

type ErrJson interface {

    RenderErr(v int)

}

func RenderErr(v int) map[string]interface{} {

    var returnMap = map[string]interface{} {
        "error": http.StatusText(v),
        "code": v,
    }

    return returnMap

}

然后,在我的控制器代码中,我尝试使用以下方式测试这个方法:

fmt.Println(ErrJson.RenderErr(400))

然而,我得到了以下错误:

controllers\FoodController.go:25: cannot use 400 (type int) as type
ErrorResponces.ErrJson in function argument:
int does not implement ErrorResponces.ErrJson (missing RenderErr method)

controllers\FoodController.go:25: not enough arguments in call to
ErrorResponces.ErrJson.RenderErr controllers\FoodController.go:25:
ErrorResponces.ErrJson.RenderErr(400) used as value

我很难弄清楚这个错误具体在说什么。

英文:

I have written a very simple Go app using the Martini library. When putting together a simple REST API example I wanted to render JSON data back to the user when an error occurred like:

{
    error: "Document Not Found",
    code: 404
}

I'm using the following code to return a map that Martini can render into JSON.
package ErrorResponces

import "net/http"

type ErrJson interface {

	RenderErr(v int)

}

func RenderErr(v int) map [string]interface{} {

	var returnMap = map[string]interface{} {
		"error": http.StatusText(v),
		"code": v,
	}

	return returnMap

}

Later in my controller code I try and test this method using

fmt.Println(ErrJson.RenderErr(400))

However I get the following error:

> controllers\FoodController.go:25: cannot use 400 (type int) as type
> ErrorResponces.ErrJson in function argument:
> int does not implement ErrorResponces.ErrJson (missing RenderErr method)
>
> controllers\FoodController.go:25: not enough arguments in call to
> ErrorResponces.ErrJson.RenderErr controllers\FoodController.go:25:
> ErrorResponces.ErrJson.RenderErr(400) used as value

I'm having a hard time figuring out exactly what this error is talking about.

答案1

得分: 2

看起来你试图直接在接口类型上调用函数,而不是在实现该接口的对象上调用函数。

这是一个返回JSON数据的简单示例:

package main

import (
  "encoding/json"
  "github.com/codegangsta/martini"
  "net/http"
)

func Encode(v ...interface{}) (string, error) {
  var data interface{} = v
  if v == nil {
    // 使空结果产生 `[]` 而不是 `null`
    data = []interface{}{}
  } else if len(v) == 1 {
    data = v[0]
  }
  b, err := json.Marshal(data)
  return string(b), err
}

func RenderErr(v int) map[string]interface{} {
  var returnMap = map[string]interface{}{
    "error": http.StatusText(v),
    "code":  v,
  }

  return returnMap
}

func main() {
  m := martini.Classic()
  m.Get("/", func(c martini.Context, w http.ResponseWriter, r *http.Request) string {
    w.Header().Set("Content-Type", "application/json")

    str, err := Encode(RenderErr(400))
    if err != nil {
      panic(err)
    }

    return str
  })
  m.Run()
}

如果你想使用你的接口想法,你可以这样做(我试图复制你基本上在做什么的代码):

package main

import (
  "encoding/json"
  "github.com/codegangsta/martini"
  "net/http"
)

func Encode(v ...interface{}) (string, error) {
  var data interface{} = v
  if v == nil {
    // 使空结果产生 `[]` 而不是 `null`
    data = []interface{}{}
  } else if len(v) == 1 {
    data = v[0]
  }
  b, err := json.Marshal(data)
  return string(b), err
}

type ErrJson interface {
  RenderErr() string
}

type ErrJsonCode int

func (e ErrJsonCode) RenderErr() string {
  var returnMap = map[string]interface{}{
    "error": http.StatusText(int(e)),
    "code":  int(e),
  }

  str, err := Encode(returnMap)
  if err != nil {
    panic(err)
  }

  return str
}

func main() {
  m := martini.Classic()
  m.Get("/", func(c martini.Context, w http.ResponseWriter, r *http.Request) string {
    w.Header().Set("Content-Type", "application/json")
    return ErrJsonCode(400).RenderErr()
  })
  m.Run()
}

不过,我不确定我会这样设计。我可能会使它更通用,支持多种内容类型,并且不将错误与其内容类型绑定在一起。这是一篇关于使用Martini构建RESTful API的不错的文章:http://0value.com/build-a-restful-API-with-Martini(它使用了一些高级概念)。

英文:

It seems that you're trying to called a function directly on an interface type instead of an object which implements that interface.

Here's a simple example that returns JSON data:

package main

import (
  "encoding/json"
  "github.com/codegangsta/martini"
  "net/http"
)

func Encode(v ...interface{}) (string, error) {
  var data interface{} = v
  if v == nil {
    // So that empty results produces `[]` and not `null`
    data = []interface{}{}
  } else if len(v) == 1 {
    data = v[0]
  }
  b, err := json.Marshal(data)
  return string(b), err
}

func RenderErr(v int) map[string]interface{} {
  var returnMap = map[string]interface{}{
    "error": http.StatusText(v),
    "code":  v,
  }

  return returnMap
}

func main() {
  m := martini.Classic()
  m.Get("/", func(c martini.Context, w http.ResponseWriter, r *http.Request) string {
    w.Header().Set("Content-Type", "application/json")

    str, err := Encode(RenderErr(400))
    if err != nil {
      panic(err)
    }

    return str
  })
  m.Run()
}

If you wanted to use your interface idea, you could do something like this (I tried to copy what you were basically doing):

package main

import (
  "encoding/json"
  "github.com/codegangsta/martini"
  "net/http"
)

func Encode(v ...interface{}) (string, error) {
  var data interface{} = v
  if v == nil {
    // So that empty results produces `[]` and not `null`
    data = []interface{}{}
  } else if len(v) == 1 {
    data = v[0]
  }
  b, err := json.Marshal(data)
  return string(b), err
}

type ErrJson interface {
  RenderErr() string
}

type ErrJsonCode int

func (e ErrJsonCode) RenderErr() string {
  var returnMap = map[string]interface{}{
    "error": http.StatusText(int(e)),
    "code":  int(e),
  }

  str, err := Encode(returnMap)
  if err != nil {
    panic(err)
  }

  return str
}

func main() {
  m := martini.Classic()
  m.Get("/", func(c martini.Context, w http.ResponseWriter, r *http.Request) string {
    w.Header().Set("Content-Type", "application/json")
    return ErrJsonCode(400).RenderErr()
  })
  m.Run()
}

I'm not sure I would design it like this though. I would probably make it more generic and have it support multiple content types, and not have an error tied to its content type. Here is a decent article about building a restful API with Martini: http://0value.com/build-a-restful-API-with-Martini (it uses some advanced concepts).

huangapple
  • 本文由 发表于 2013年12月21日 13:41:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/20715905.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定