Interface 如何访问接口的属性

Interface 如何访问接口的属性,interface,go,Interface,Go,我打算在两个响应结构的头部和主体中使用HTTP状态代码。Bu表示,无需将状态代码两次设置为函数参数,并再次设置为结构,以避免冗余 JSON()的参数response是一个允许接受两个结构的接口。编译器引发以下异常: response.Status undefined (type interface {} has no field or method Status) 因为响应字段不能有status属性。是否有其他方法避免设置两次状态代码 type Response struct { St

我打算在两个响应结构的头部和主体中使用HTTP状态代码。Bu表示,无需将状态代码两次设置为函数参数,并再次设置为结构,以避免冗余

JSON()
的参数
response
是一个允许接受两个结构的接口。编译器引发以下异常:

response.Status undefined (type interface {} has no field or method Status)
因为响应字段不能有status属性。是否有其他方法避免设置两次状态代码

type Response struct {
    Status int         `json:"status"`
    Data   interface{} `json:"data"`
}

type ErrorResponse struct {
    Status int      `json:"status"`
    Errors []string `json:"errors"`
}

func JSON(rw http.ResponseWriter, response interface{}) {
    payload, _ := json.MarshalIndent(response, "", "    ")
    rw.WriteHeader(response.Status)
    ...
}

接口没有属性,因此需要从接口提取结构。要做到这一点,您需要使用


接口没有属性,因此需要从接口提取结构。要做到这一点,您需要使用


rw.WriteHeader(response.Status)
中的类型
response
interface{}
。在Go中,需要显式断言基础结构的类型,然后访问字段:

func JSON(rw http.ResponseWriter, response interface{}) {
    payload, _ := json.MarshalIndent(response, "", "    ")
    switch r := response.(type) {
    case ErrorResponse:
        rw.WriteHeader(r.Status)
    case Response:
        rw.WriteHeader(r.Status) 
    }
    ...
}
但是,更好、更可取的方法是为您的响应定义一个通用接口,该接口具有获取响应状态的方法:

type Statuser interface {
    Status() int
}

// You need to rename the fields to avoid name collision.
func (r Response) Status() int { return r.ResStatus }
func (r ErrorResponse) Status() int { return r.ResStatus }

func JSON(rw http.ResponseWriter, response Statuser) {
    payload, _ := json.MarshalIndent(response, "", "    ")
    rw.WriteHeader(response.Status())
    ...
}

最好将
Response
重命名为
DataResponse
,将
ResponseInterface
重命名为
Response
,IMO.

rw.WriteHeader(Response.Status)
中的
Response
类型是
接口{}
。在Go中,需要显式断言基础结构的类型,然后访问字段:

func JSON(rw http.ResponseWriter, response interface{}) {
    payload, _ := json.MarshalIndent(response, "", "    ")
    switch r := response.(type) {
    case ErrorResponse:
        rw.WriteHeader(r.Status)
    case Response:
        rw.WriteHeader(r.Status) 
    }
    ...
}
但是,更好、更可取的方法是为您的响应定义一个通用接口,该接口具有获取响应状态的方法:

type Statuser interface {
    Status() int
}

// You need to rename the fields to avoid name collision.
func (r Response) Status() int { return r.ResStatus }
func (r ErrorResponse) Status() int { return r.ResStatus }

func JSON(rw http.ResponseWriter, response Statuser) {
    payload, _ := json.MarshalIndent(response, "", "    ")
    rw.WriteHeader(response.Status())
    ...
}


最好将
Response
重命名为
DataResponse
ResponseInterface
重命名为
Response
,IMO.

为什么你只使用
Response.(ErrorResponse)
?@user3147268:我不明白这个问题,使用
Response.(ErrorResponse)
Response有什么区别。(响应)
?区别在于您得到的是
ErrorResponse
响应
。如果您希望它们可以互换,请创建一个新的界面,以获得所需的属性。这就是为什么您只使用
响应的方法。(ErrorResponse)
?@user3147268:我不明白这个问题,使用
响应(ErrorResponse)
响应(response)有什么区别吗
?区别在于您得到了一个
错误响应
或者您得到了一个
响应
。如果您希望它们可以互换,请创建一个新的接口,以获得所需的属性。这将是感谢解决方案的方法。现在最好将状态代码设置为新参数的两倍,并在结构内部,还是编写two实现相同功能的新函数和接口:
DataResponse
可能比
OKResponse
更好。
Status()int
接口的另一个名称是
Statuser
或只是
Status
(前者听起来不太正确,但这类
…er
非单词接口有一个优先级)。谢谢@Dave-C。对答案做了一点修改。@user3147268 IMO最好使用该接口。您还可以创建一个实现
状态()的基本公共结构
但这只是过火了。在围棋中重复一点总是可以的。命名是你的首选。选择你喜欢的任何东西。作为旁注,在围棋中,如果一个接口包装了一个方法
M
,他们称这个接口为“M'er”。看看
io.Reader
io.Writer
,和
io.ReadWriteCloser
来了解这个想法。感谢e解决方案。现在是将状态代码设置为新参数的两倍并在结构内部,还是编写两个新函数和一个接口以实现相同的效果?注意:
DataResponse
可能比
OKResponse
更好。
status()的另一个名称int
接口将是
Statuser
或仅仅是
Status
(前者听起来不正确,但这类
…er
非文字接口有优先权)。谢谢@Dave-C。将答案稍微更改了一点。@user3147268我认为最好使用该接口。您还可以创建一个实现
Status()的基本公共结构
但这只是过火了。在围棋中重复一点总是可以的。命名是你的首选。选择你喜欢的任何东西。作为旁注,在围棋中,如果一个接口包装了一个方法
M
,他们称这个接口为“M'er”。看看
io.Reader
io.Writer
,和
io.ReadWriteCloser
,了解一下。