英文:
How to make function work with different input types?
问题
我有一个简单的通用请求结构体,用于在我的应用程序中进行GET请求:
package api
import (
"net/http"
"time"
"log"
"app/errors"
)
type Request struct {
Url string
}
func (request *Request) Run(responseObject *AppStatusInfo) *errors.Error {
req, requestErr := http.NewRequest(http.MethodGet, request.Url, nil)
req.Header.Set("Content-Type", "application/json")
timeout := time.Duration(5 * time.Second)
client := &http.Client{
Timeout: timeout,
}
resp, requestErr := client.Do(req)
if requestErr != nil {
return &errors.UnknownError
}
decodeError := DecodeJsonRequestBody(resp, &responseObject)
if (decodeError != nil) {
return &errors.UnknownError
}
defer resp.Body.Close()
return nil
}
这里的responseObject
是一个指向AppStatusInfo
类型的指针,它是一个带有一些字段的结构体。
我像这样运行它,以获取应用程序状态信息并将其放入appStatusInfo
对象中:
var appStatusInfo AppStatusInfo
req := Request{
Url:config.Config.ApiUrl,
}
req.Run(&appStatusInfo)
所以,这段代码运行得很好。
但是,当我想要将Request
泛化以接受其他类型的响应,比如UserProducts
时,我不知道如何在不将responseObject *AppStatusInfo
替换为responseObject interface{}
的情况下实现,然后使用responseObject.(UserProducts)
进行类型转换,我认为这可以改进。
因此,由于没有泛型,我该如何使Request.Run()
接受不同类型并返回相应的对象呢?
英文:
I have this simple generic Request struct to make get requests in my app:
package api
import (
"net/http"
"time"
"log"
"app/errors"
)
type Request struct {
Url string
}
func (request *Request) Run(responseObject *AppStatusInfo) *errors.Error {
req, requestErr := http.NewRequest(http.MethodGet, request.Url, nil)
req.Header.Set("Content-Type", "application/json")
timeout := time.Duration(5 * time.Second)
client := &http.Client{
Timeout: timeout,
}
resp, requestErr := client.Do(req)
if requestErr != nil {
return &errors.UnknownError
}
decodeError := DecodeJsonRequestBody(resp, &responseObject)
if (decodeError != nil) {
return &errors.UnknownError
}
defer resp.Body.Close()
return nil
}
Here responseObject
has pointer of type AppStatusInfo which is a struct with some fields.
I run it like this to get app status information and put it inside appStatusInfo
object:
var appStatusInfo AppStatusInfo
req := Request{
Url:config.Config.ApiUrl,
}
req.Run(&appStatusInfo)
So, this code runs fine.
But, when I want to generalize Request to accept other types of responses, like UserProducts
, I don't know how to do it without replacing responseObject *AppStatusInfo
with responseObject interface{}
, then casting it with responseObject.(UserProducts) which I think can be improved.
So, as soon as there are no generics, how do I make Request.Run()
accept different types and return respective objects?
答案1
得分: 1
假设DecodeJsonRequestBody
将第二个参数传递给json.Unmarshal或json.Decoder.Decode,那么可以按照以下方式进行修改。我只展示了更改的行:
func (request *Request) Run(responseObject interface{}) *errors.Error {
...
resp, requestErr := client.Do(req)
if requestErr != nil {
return &errors.UnknownError
}
defer resp.Body.Close() // 在执行其他操作之前延迟关闭
...
decodeError := DecodeJsonRequestBody(resp, responseObject) // 不要取responseObject的地址
...
}
你可以这样调用它:
var up UserProducts
err = r.Run(&up)
var asi AppStatusInfo
err = r.Run(&asi)
不需要类型断言和类型转换。
英文:
Assuming that DecodeJsonRequestBody
passes the second argument to json.Unmarshal or json.Decoder.Decode, then write it like this. I show the changed lines only:
func (request *Request) Run(responseObject interface{}) *errors.Error {
...
resp, requestErr := client.Do(req)
if requestErr != nil {
return &errors.UnknownError
}
defer resp.Body.Close() // defer close before doing anything else
...
decodeError := DecodeJsonRequestBody(resp, responseObject) // don't take address of responseObject
...
}
You can call it like this:
var up UserProducts
err = r.Run(&up)
var asi AppStatusInfo
err = r.Run(&asi)
Type assertions and type conversions are not required.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论