2015-05-20 42 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