英文:
Semantic way of http.Response receiver functions in Go
问题
我刚开始学习GO,并编写了这段代码,用于将http.Response.Body
写入os.Stdout
或文件中,但我对其语义不太满意。
我希望http.Response
结构体具有这些接收函数,以便在整个应用程序中更轻松地使用它。
我知道答案可能会被标记为主观意见,但我仍然想知道,是否有更好的编写方式?是否有某种最佳实践?
package main
import (
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
)
type httpResp http.Response
func main() {
res, err := http.Get("http://www.stackoverflow.com")
if err != nil {
fmt.Println("Error: ", err)
os.Exit(1)
}
defer res.Body.Close()
response := httpResp(*res)
response.toFile("stckovrflw.html")
response.toStdOut()
}
func (r httpResp) toFile(filename string) {
str, err := ioutil.ReadAll(r.Body)
if err != nil {
panic(err)
}
ioutil.WriteFile(filename, []byte(str), 0666)
}
func (r httpResp) toStdOut() {
_, err := io.Copy(os.Stdout, r.Body)
if err != nil {
panic(err)
}
}
另外,有没有办法使http.Get
方法输出一个自定义类型,该类型已经具有这些接收函数的访问权限,而无需进行类型转换?这样我就可以像这样做:
func main() {
res, err := http.Get("http://www.stackoverflow.com")
if err != nil {
fmt.Println("Error: ", err)
os.Exit(1)
}
defer res.Body.Close()
res.toFile("stckovrflw.html")
res.toStdOut()
}
谢谢!
英文:
I just started learning GO and wrote this piece of code that writes an http.Response.Body
to os.Stdout
or to a file, but I'm not happy about the semantics of this.
I want the http.Response
struct to have these receiver functions, so I can use it more easily throughout the entire app.
I know that the answers might get flagged as opinionated, but I still wonder, is there a better way of writing this?
Is there some sort of best practice?
package main
import (
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
)
type httpResp http.Response
func main() {
res, err := http.Get("http://www.stackoverflow.com")
if err != nil {
fmt.Println("Error: ", err)
os.Exit(1)
}
defer res.Body.Close()
response := httpResp(*res)
response.toFile("stckovrflw.html")
response.toStdOut()
}
func (r httpResp) toFile(filename string) {
str, err := ioutil.ReadAll(r.Body)
if err != nil {
panic(err)
}
ioutil.WriteFile(filename, []byte(str), 0666)
}
func (r httpResp) toStdOut() {
_, err := io.Copy(os.Stdout, r.Body)
if err != nil {
panic(err)
}
}
On a side note, is there a way to make the http.Get
method spit out a custom type that already has access to these receiver functions without the need for casting? So i could do something like this:
func main() {
res, err := http.Get("http://www.stackoverflow.com")
if err != nil {
fmt.Println("Error: ", err)
os.Exit(1)
}
defer res.Body.Close()
res.toFile("stckovrflw.html")
res.toStdOut()
}
Thanks!
答案1
得分: 2
你不需要实现这些函数。*http.Response
已经实现了 io.Writer
接口(参考链接):
package main
import (
"net/http"
"os"
)
func main() {
r := &http.Response{}
r.Write(os.Stdout)
}
在上面的示例中,零值打印出:
HTTP/0.0 000 status code 0
Content-Length: 0
Playground: https://play.golang.org/p/2AUEAUPCA8j
如果你需要在写入方法中添加额外的业务逻辑,你可以在自定义类型中嵌入 *http.Response
:
type RespWrapper struct {
*http.Response
}
func (w *RespWrapper) toStdOut() {
_, err := io.Copy(os.Stdout, w.Body)
if err != nil {
panic(err)
}
}
但是你必须使用 *http.Response
构造一个 RespWrapper
类型的变量:
func main() {
// 带有虚假 body 的 resp
r := &http.Response{Body: io.NopCloser(strings.NewReader("foo"))}
// 或者 r, _ := http.Get("example.com")
// 构造 wrapper
wrapper := &RespWrapper{Response: r}
wrapper.toStdOut()
}
有没有办法使
http.Get
方法输出自定义类型?
不,http.Get
的返回类型是 (resp *http.Response, err error)
,这是函数签名的一部分,你不能改变它。
英文:
You don't have to implement these functions. *http.Response
already implements io.Writer
:
> Write writes r to w in the HTTP/1.x server response format, including the status line, headers, body, and optional trailer.
package main
import (
"net/http"
"os"
)
func main() {
r := &http.Response{}
r.Write(os.Stdout)
}
In the example above, the zero value prints:
> HTTP/0.0 000 status code 0
>
> Content-Length: 0
Playground: https://play.golang.org/p/2AUEAUPCA8j
<hr>
In case you need additional business logic in the write methods, you can embed *http.Response
in your defined type:
type RespWrapper struct {
*http.Response
}
func (w *RespWrapper) toStdOut() {
_, err := io.Copy(os.Stdout, w.Body)
if err != nil {
panic(err)
}
}
But then you must construct a variable of type RespWrapper
with the *http.Response
:
func main() {
// resp with a fake body
r := &http.Response{Body: io.NopCloser(strings.NewReader("foo"))}
// or r, _ := http.Get("example.com")
// construct the wrapper
wrapper := &RespWrapper{Response: r}
wrapper.toStdOut()
}
> is there a way to make the http.Get method spit out a custom type
No, the return types of http.Get
are (resp *http.Response, err error)
, that's part of the function signature, you can't change it.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论