2015-05-20 45 views
0

我的意图是在两个响应结构的头部和主体中使用HTTP状态码。如果没有设置状态码两次作为函数参数,并且再次为结构设置以避免冗余。如何访问接口的属性

参数responseJSON()是一个接口,允许两个结构被接受。编译器会抛出以下异常:

response.Status undefined (type interface {} has no field or method 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) 
    ... 
} 

回答

4

类型responserw.WriteHeader(response.Status)interface{}。在走,你需要明确地断言底层结构的类型,然后访问场:

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()) 
    ... 
} 

而且最好重新命名ResponseDataResponseResponseInterfaceResponse,IMO:为得到响应的状态的方法。

+0

感谢您的解决方案。现在是否更好,因此将状态代码设置为新参数两次并在结构中设置两次,或者编写两个新函数和一个实现相同的接口? – user3147268

+0

nit:'DataResponse'可能比'OKResponse'好。 'Status()int'接口的另一个名字是'Statuser'或者'Status'(前者听起来不正确,但是这样的''er'非字接口有优先权。 –

+0

Thanks @ Dave-C。稍微改变了答案。 –

1

接口没有属性,所以你需要从接口中提取结构。要做到这一点,你使用type assertion

if response, ok := response.(ErrorResponse); ok { 
    rw.WriteHeader(response.Status) 
    ... 
+0

你为什么只使用'response。(ErrorResponse)'? – user3147268

+0

@ user3147268:我不明白这个问题 – JimB

+0

使用'response.(ErrorResponse)'或'response。(Response)'是否有区别? – user3147268