去除重复代码的Go解决方案(defer, net/http)

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

Go solution for removing duplicate code (defer, net/http)

问题

我可以帮你翻译代码,但是请注意,我只能返回翻译好的部分,不会回答关于翻译的问题。

以下是你提供的Go代码的翻译:

func (api *ApiResource) create(request *restful.Request, response *restful.Response) {
    account := &DefaultAccount
    err := request.ReadEntity(account)
    if err != nil {
        response.WriteErrorString(http.StatusInternalServerError, err.Error())
        return
    }
    tmpl := data_transformer.ParseTemplate("xml/accAdd.xml")
    payload := data_transformer.RenderTemplate(tmpl, account)
    resp, err := http.Post(url, "application/xml", payload)
    if err != nil {
        response.WriteErrorString(http.StatusInternalServerError, err.Error())
        return
    }

    // Body closes when either at the end of the function or at return
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)

    aResp := new(AResp)
    err = xml.Unmarshal(body, aResp)
    if err != nil {
        fmt.Printf("error: %v", err)
        return
    }
    response.WriteHeader(http.StatusCreated)
    response.WriteEntity(aResp)
}

func (api *ApiResource) updateLimit(request *restful.Request, response *restful.Response) {
    account := &DefaultLimit
    err := request.ReadEntity(account)
    if err != nil {
        response.WriteErrorString(http.StatusInternalServerError, err.Error())
        return
    }
    tmpl := data_transformer.ParseTemplate("xml/addLimit.xml")
    payload := data_transformer.RenderTemplate(tmpl, account)
    resp, err := http.Post(url, "application/xml", payload)
    if err != nil {
        response.WriteErrorString(http.StatusInternalServerError, err.Error())
        return
    }

    // Body closes when either at the end of the function or at return
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)

    aResp := new(AResp)
    err = xml.Unmarshal(body, aResp)
    if err != nil {
        fmt.Printf("error: %v", err)
        return
    }
    response.WriteHeader(http.StatusCreated)
    response.WriteEntity(aResp)
}

你想以一种优雅的方式使用Go风格来消除重复的代码。如果你将它们移动到单独的函数中,所有的defer和net/http包是否会按预期工作,对于不同的调用和xml文件加载?

对于这个问题,一个好的Go类型解决方案是使用函数参数和返回值。你可以将重复的代码提取到一个单独的函数中,并将需要变化的部分作为参数传递给函数。然后,你可以在不同的调用中调用这个函数,并使用返回的结果。

以下是一个示例:

func (api *ApiResource) create(request *restful.Request, response *restful.Response) {
    account := &DefaultAccount
    err := request.ReadEntity(account)
    if err != nil {
        response.WriteErrorString(http.StatusInternalServerError, err.Error())
        return
    }
    aResp := processRequest(url, "xml/accAdd.xml", account, response)
    response.WriteHeader(http.StatusCreated)
    response.WriteEntity(aResp)
}

func (api *ApiResource) updateLimit(request *restful.Request, response *restful.Response) {
    account := &DefaultLimit
    err := request.ReadEntity(account)
    if err != nil {
        response.WriteErrorString(http.StatusInternalServerError, err.Error())
        return
    }
    aResp := processRequest(url, "xml/addLimit.xml", account, response)
    response.WriteHeader(http.StatusCreated)
    response.WriteEntity(aResp)
}

func processRequest(url, templatePath string, account *Account, response *restful.Response) *AResp {
    tmpl := data_transformer.ParseTemplate(templatePath)
    payload := data_transformer.RenderTemplate(tmpl, account)
    resp, err := http.Post(url, "application/xml", payload)
    if err != nil {
        response.WriteErrorString(http.StatusInternalServerError, err.Error())
        return nil
    }

    // Body closes when either at the end of the function or at return
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)

    aResp := new(AResp)
    err = xml.Unmarshal(body, aResp)
    if err != nil {
        fmt.Printf("error: %v", err)
        return nil
    }
    return aResp
}

在这个示例中,我们将重复的代码提取到了processRequest函数中,并将需要变化的部分作为参数传递给函数。这样,你就可以在不同的调用中调用processRequest函数,并使用返回的结果。同时,defer语句和net/http包的功能仍然会按预期工作。

英文:

I have a below code in Go:

func (api *ApiResource) create(request *restful.Request, response *restful.Response) {
account := &DefaultAccount
err := request.ReadEntity(account)
if err != nil {
response.WriteErrorString(http.StatusInternalServerError, err.Error())
return
}
tmpl := data_transformer.ParseTemplate("xml/accAdd.xml")
payload := data_transformer.RenderTemplate(tmpl, account)
resp, err := http.Post(url, "application/xml", payload)
if err != nil {
response.WriteErrorString(http.StatusInternalServerError, err.Error())
return
}
// Body closes when either at the end of the function or at return
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
aResp := new(AResp)
err = xml.Unmarshal(body, aResp)
if err != nil {
fmt.Printf("error: %v", err)
return
}
response.WriteHeader(http.StatusCreated)
response.WriteEntity(aResp)
}
func (api *ApiResource) updateLimit(request *restful.Request, response *restful.Response) {
account := &DefaultLimit
err := request.ReadEntity(account)
if err != nil {
response.WriteErrorString(http.StatusInternalServerError, err.Error())
return
}
tmpl := data_transformer.ParseTemplate("xml/addLimit.xml")
payload := data_transformer.RenderTemplate(tmpl, account)
resp, err := http.Post(url, "application/xml", payload)
if err != nil {
response.WriteErrorString(http.StatusInternalServerError, err.Error())
return
}
// Body closes when either at the end of the function or at return
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
aResp := new(AResp)
err = xml.Unmarshal(body, aResp)
if err != nil {
fmt.Printf("error: %v", err)
return
}
response.WriteHeader(http.StatusCreated)
response.WriteEntity(aResp)
}

I want to be able to remove duplicate codes in an elegant way Go style.

If I do remove them and put them in separate function, would all defer and net/http package work as expected for different calls and xml file loads?

What is a good Go type solutions for this?

答案1

得分: 1

你可以将几乎整个函数分离出来,只需将“account”和要读取的XML文件传递给它。

此外,当从流中读取时,最好使用xml.Decoder而不是xml.Unmarshal

func updateEntity(response *restful.Response, fn string, iface interface{}) {
    tmpl := data_transformer.ParseTemplate("xml/" + fn)
    payload := data_transformer.RenderTemplate(tmpl, iface)
    resp, err := http.Post(url, "application/xml", payload)
    if err != nil {
        response.WriteErrorString(http.StatusInternalServerError, err.Error())
        return
    }

    defer resp.Body.Close()
    dec := xml.NewDecoder(resp.Body)
    body, err := ioutil.ReadAll(resp.Body)

    aResp := &AResp{}
    err = dec.Decode(aResp)
    if err != nil {
        fmt.Printf("error: %v", err)
        return
    }
    response.WriteHeader(http.StatusCreated)
    response.WriteEntity(aResp)
}

func (*ApiResource) create(request *restful.Request, response *restful.Response) {
    account := &DefaultAccount
    err := request.ReadEntity(account)
    if err != nil {
        response.WriteErrorString(http.StatusInternalServerError, err.Error())
        return
    }
    updateEntity(response, "accAdd.xml", account)
}

func (*ApiResource) updateLimit(request *restful.Request, response *restful.Response) {
    account := &DefaultLimit
    err := request.ReadEntity(account)
    if err != nil {
        response.WriteErrorString(http.StatusInternalServerError, err.Error())
        return
    }
    updateEntity(response, "addLimit.xml", account)
}

请注意,这只是代码的翻译部分,不包括其他内容。

英文:

You can separate almost the whole function and just pass to it the "account" and the xml file to read.

Also it's a better practice to use xml.Decoder instead of xml.Unmarshal when reading from streams.

func updateEntity(response *restful.Response, fn string, iface interface{}) {
tmpl := data_transformer.ParseTemplate("xml/" + fn)
payload := data_transformer.RenderTemplate(tmpl, iface)
resp, err := http.Post(url, "application/xml", payload)
if err != nil {
response.WriteErrorString(http.StatusInternalServerError, err.Error())
return
}
defer resp.Body.Close()
dec := xml.NewDecoder(resp.Body)
body, err := ioutil.ReadAll(resp.Body)
aResp := &AResp{}
err = dec.Decode(aResp)
if err != nil {
fmt.Printf("error: %v", err)
return
}
response.WriteHeader(http.StatusCreated)
response.WriteEntity(aResp)
}
func (*ApiResource) create(request *restful.Request, response *restful.Response) {
account := &DefaultAccount
err := request.ReadEntity(account)
if err != nil {
response.WriteErrorString(http.StatusInternalServerError, err.Error())
return
}
updateEntity(response, "accAdd.xml", account)
}
func (*ApiResource) updateLimit(request *restful.Request, response *restful.Response) {
account := &DefaultLimit
err := request.ReadEntity(account)
if err != nil {
response.WriteErrorString(http.StatusInternalServerError, err.Error())
return
}
updateEntity(response, "addLimit.xml", account)
}

huangapple
  • 本文由 发表于 2014年9月29日 16:33:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/26095631.html
匿名

发表评论

匿名网友

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

确定