lai*_*e9m 30 string http go slice
我已经看到了三种将内容写入HTTP响应的方法:
func Handler(w http.ResponseWriter, req *http.Request) {
io.WriteString(w, "blabla.\n")
}
Run Code Online (Sandbox Code Playgroud)
和:
func Handler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("blabla\n"))
}
Run Code Online (Sandbox Code Playgroud)
还有:
fmt.Fprintf(w, "blabla")
Run Code Online (Sandbox Code Playgroud)
他们之间有什么区别?哪一个更喜欢使用?
icz*_*cza 56
io.Writer输出流表示可以写入字节序列的目标.在Go中,这是由通用io.Writer接口捕获的:
type Writer interface {
Write(p []byte) (n int, err error)
}
Run Code Online (Sandbox Code Playgroud)
具有此单一Write()方法的所有内容都可以用作输出,例如磁盘上的文件(os.File),网络连接(net.Conn)或内存缓冲区(bytes.Buffer).
该http.ResponseWriter用来配置HTTP响应并将数据发送给客户端也是这样的io.Writer,你要发送(响应正文)通过调用(不一定只是一次)组装的数据ResponseWriter.Write()(这是实现一般io.Writer) .这是您对http.ResponseWriter接口实现的唯一保证.
WriteString()现在开始WriteString().通常我们想要将文本数据写入io.Writer.是的,我们可以通过简单地转换string为a来实现[]byte,例如
w.Write([]byte("Hello"))
Run Code Online (Sandbox Code Playgroud)
它按预期工作.然而,这是一个非常频繁的操作,因此有一个"通常"接受的方法,由未io.StringWriter导出的接口捕获:
type StringWriter interface {
WriteString(s string) (n int, err error)
}
Run Code Online (Sandbox Code Playgroud)
这种方法可以写一个string值而不是一个[]byte.因此,如果某些东西(也实现了io.Writer)实现了这个方法,你可以简单地传递string值而不进行[]byte转换.这似乎是代码中的一个小的简化,但它不止于此.转换string为[]byte必须制作string内容的副本(因为string值在Go中是不可变的),因此如果string"更大"和/或您必须多次执行此操作,则会有一些明显的开销.
取决于a的性质和实现细节io.Writer,可能的是,可以在string不转换它的情况下写入a的内容,[]byte从而避免上述开销.
例如,如果a io.Writer是写入内存缓冲区的东西(bytes.Buffer就是这样一个例子),它可以使用内置copy()函数:
复制内置函数将元素从源切片复制到目标切片.(作为一种特殊情况,它还会将字符串中的字节复制到一个字节片段.)
的copy()可用于一个内容(字节)复制string到一个[]byte不转换string到[]byte,例如:
buf := make([]byte, 100)
copy(buf, "Hello")
Run Code Online (Sandbox Code Playgroud)
现在有一个"实用程序"函数io.WriteString()将a string写入io.Writer.但它通过首先检查传递的(动态类型)io.Writer是否有WriteString()方法来实现这一点,如果是,那么将使用它(其实现可能更有效).如果传递的io.Writer没有这样的方法,那么通常的convert-to-byte-slice-and-write-it-way方法将被用作"后备".
您可能认为这WriteString()只会在内存缓冲区中占上风,但事实并非如此.Web请求的响应也经常被缓冲(使用内存缓冲区),因此它也可以提高性能http.ResponseWriter.如果你看一下http.ResponseWriter它的实现:它是未实现的类型http.response(server.go目前是第308行),它确实实现了WriteString()(目前第1212行),所以它确实意味着一种改进.
总而言之,无论何时写入string值,建议使用io.WriteString()它,因为它可能更有效(更快).
fmt.Fprintf()您应该将此视为一种方便简单的方法,为您要编写的数据添加更多格式,以换取性能稍差的方法.
因此,fmt.Fprintf()如果您想要string以简单的方式创建格式,请使用,例如:
name := "Bob"
age := 23
fmt.Fprintf(w, "Hi, my name is %s and I'm %d years old.", name, age)
Run Code Online (Sandbox Code Playgroud)
这将导致以下内容string:
Hi, my name is Bob and I'm 23 years old.
Run Code Online (Sandbox Code Playgroud)
有一点你不能忘记:fmt.Fprintf()期望一个格式字符串,因此它将被预处理,而不是按原样写入输出.作为一个简单的例子:
fmt.Fprintf(w, "100 %%")
Run Code Online (Sandbox Code Playgroud)
您希望"100 %%"将写入输出(带有2个%字符),但只会发送一个,因为格式字符串%是一个特殊字符,并且%%只会在输出中产生一个.
如果您只想%使用string包编写,请使用fmt不需要格式的包fmt.Fprint():
fmt.Fprint(w, "Hello")
Run Code Online (Sandbox Code Playgroud)
使用该string软件包的另一个好处是,您也可以编写其他类型的值,而不仅仅是fmts,例如
fmt.Fprint(w, 23, time.Now())
Run Code Online (Sandbox Code Playgroud)
(当然,如何将任何值转换为string-and到最终字节序列的规则在string包的文档中已经很好地定义了.)
对于"简单"格式化输出,fmt包可能没问题.对于复杂的输出文档,请考虑使用fmt(对于一般文本)和text/template(每当输出为HTML时).
html/template为了完整起见,我们应该提到,您希望作为Web响应发送的内容通常由支持"流式传输"结果的"内容"生成.一个示例可以是JSON响应,它是从结构或映射生成的.
在这种情况下,它往往更有效的传递/移交http.ResponseWriter这是http.ResponseWriter这个东西,如果它支持将结果写到一个io.Writer关于即时.
一个很好的例子就是生成JSON响应.当然,您可以将一个对象编组为JSON io.Writer,它会返回一个字节切片,您只需通过调用即可发送json.Marshal().
但是,让ResponseWriter.Write()包知道你有一个更高效json,最终你想要将结果发送给它.这样就不必首先在缓冲区中生成JSON文本,然后将其写入响应中然后丢弃.您可以io.Writer通过调用json.Encoder来创建一个新的,您可以将其json.NewEncoder()作为一个传递http.ResponseWriter,并io.Writer在此之后调用将直接将JSON结果写入您的响应编写器.
这里的一个缺点是,如果生成JSON响应失败,您可能会有一个部分发送/已提交的响应,您无法收回.如果这对您来说是个问题,那么除了在缓冲区中生成响应之外,您实际上没有其他选择,如果编组成功,那么您可以立即编写完整的响应.
小智 6
从这里可以看到(ResponseWriter),它是一个带Write([]byte) (int, error)方法的接口.
因此,在io.WriteString和fmt.Fprintf两个正在作家作为第一个参数,这也是一个接口的包装Write(p []byte) (n int, err error)方法
type Writer interface {
Write(p []byte) (n int, err error)
}
Run Code Online (Sandbox Code Playgroud)
所以当你调用io.WriteString(w,"blah")时请点击此处
func WriteString(w Writer, s string) (n int, err error) {
if sw, ok := w.(stringWriter); ok {
return sw.WriteString(s)
}
return w.Write([]byte(s))
}
Run Code Online (Sandbox Code Playgroud)
或fmt.Fprintf(w,"blabla")在这里查看
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
p := newPrinter()
p.doPrintf(format, a)
n, err = w.Write(p.buf)
p.free()
return
}
Run Code Online (Sandbox Code Playgroud)
你只是ResponseWriter在两个方法中传递变量时间接调用Write 方法.
那么为什么不直接使用它来调用它w.Write([]byte("blabla\n")).我希望你得到你的答案.
PS:如果你想将它作为JSON响应发送,还有一种不同的使用方式.
json.NewEncoder(w).Encode(wrapper)
//Encode take interface as an argument. Wrapper can be:
//wrapper := SuccessResponseWrapper{Success:true, Data:data}
Run Code Online (Sandbox Code Playgroud)