2 回答

TA貢獻1840條經(jīng)驗 獲得超5個贊
io.Writer
輸出流表示您可以向其寫入字節(jié)序列的目標。io.Writer在 Go 中,這是由通用接口捕獲的:
type Writer interface {
Write(p []byte) (n int, err error)
}
具有這種單一Write()方法的所有內(nèi)容都可以用作輸出,例如磁盤上的文件 ( os.File)、網(wǎng)絡連接 ( net.Conn) 或內(nèi)存緩沖區(qū) ( bytes.Buffer)。
http.ResponseWriter用來配置HTTP響應和發(fā)送數(shù)據(jù)給客戶端的也是這樣一個,io.Writer你要發(fā)送的數(shù)據(jù)(響應體)是通過調(diào)用組裝的(不一定只有一次)ResponseWriter.Write()(這是實現(xiàn)通用的io.Writer) . 這是您對http.ResponseWriter接口實現(xiàn)的唯一保證(關于發(fā)送主體)。
WriteString()
現(xiàn)在繼續(xù)WriteString()。通常我們想將文本數(shù)據(jù)寫入io.Writer. 是的,我們可以簡單地通過將 轉(zhuǎn)換string為 a來做到這一點[]byte,例如
w.Write([]byte("Hello"))
按預期工作。然而,這是一個非常頻繁的操作,因此io.StringWriter接口捕獲了一個“普遍”接受的方法(從Go 1.12開始可用,在此之前它未被導出):
type StringWriter interface {
WriteString(s string) (n int, err error)
}
此方法提供了寫入string值而不是的可能性[]byte。所以如果某些東西(也實現(xiàn)了io.Writer)實現(xiàn)了這個方法,你可以簡單地傳遞string值而無需[]byte轉(zhuǎn)換。這似乎是對代碼的輕微簡化,但不僅如此。將 a 轉(zhuǎn)換string為[]byte必須復制string內(nèi)容(因為string值在 Go 中是不可變的,請在此處閱讀有關它的更多信息:golang: []byte(string) vs []byte(*string)),因此會產(chǎn)生一些開銷如果string“更大”和/或您必須多次執(zhí)行此操作,則很明顯。
根據(jù) a 的性質(zhì)和實現(xiàn)細節(jié),io.Writer可以編寫 a 的內(nèi)容string而不將其轉(zhuǎn)換為[]byte,從而避免上述開銷。
例如,如果 anio.Writer是寫入內(nèi)存緩沖區(qū)的東西(bytes.Buffer就是這樣一個例子),它可以利用內(nèi)置copy()函數(shù):
復制內(nèi)置函數(shù)將元素從源切片復制到目標切片。(作為一種特殊情況,它還將字節(jié)從字符串復制到字節(jié)片。)
可copy()用于將 a 的內(nèi)容(字節(jié))復制string到 a[]byte而無需將 轉(zhuǎn)換string為[]byte,例如:
buf := make([]byte, 100)
copy(buf, "Hello")
現(xiàn)在有一個“實用程序”函數(shù)io.WriteString()可以將 astring寫入io.Writer. 但它首先檢查傳遞的(動態(tài)類型)io.Writer是否有WriteString()方法,如果有,將使用該方法(其實現(xiàn)可能更有效)。如果傳遞io.Writer的沒有這樣的方法,那么一般的convert-to-byte-slice-and-write-that方法將被用作“后備”。
您可能認為這WriteString()只會在內(nèi)存緩沖區(qū)的情況下占優(yōu)勢,但事實并非如此。Web 請求的響應也經(jīng)常被緩沖(使用內(nèi)存緩沖區(qū)),因此它也可以提高性能http.ResponseWriter。如果您查看 : 的實現(xiàn),http.ResponseWriter它是未導出的類型http.response(server.go當前第 308 行),它確實實現(xiàn)了WriteString()(當前第 1212 行),所以它確實意味著改進。
總而言之,無論何時寫入string值,都建議使用它,io.WriteString()因為它可能更有效(更快)。
fmt.Fprintf()
您應該將此視為一種方便且簡單的方法,可以為要寫入的數(shù)據(jù)添加更多格式,以換取性能稍差。
因此fmt.Fprintf(),如果您想string以簡單的方式創(chuàng)建格式化,請使用,例如:
name := "Bob"
age := 23
fmt.Fprintf(w, "Hi, my name is %s and I'm %d years old.", name, age)
這將導致以下內(nèi)容string被寫入:
Hi, my name is Bob and I'm 23 years old.
您不能忘記的一件事:fmt.Fprintf()需要一個格式字符串,因此它將被預處理而不是按原樣寫入輸出。舉個簡單的例子:
fmt.Fprintf(w, "100 %%")
您希望"100 %%"將其寫入輸出(帶有 2 個%字符),但只會發(fā)送一個,因為格式字符串%是一個特殊字符,并且%%只會%在輸出中產(chǎn)生一個。
如果您只想string使用fmt包編寫一個,請使用fmt.Fprint()不需要格式string:
fmt.Fprint(w, "Hello")
使用該包的另一個好處fmt是您也可以編寫其他類型的值,而不僅僅是strings,例如
fmt.Fprint(w, 23, time.Now())
(當然,如何將任何值轉(zhuǎn)換為一個string- 并最終轉(zhuǎn)換為一系列字節(jié)的規(guī)則在fmt包的文檔中得到了很好的定義。)
對于“簡單”格式的輸出,fmt包可能沒問題。對于復雜的輸出文檔,請考慮使用text/template(對于一般文本)和html/template(只要輸出是 HTML)。
傳遞/移交 http.ResponseWriter
為了完整起見,我們應該提到,您希望作為 Web 響應發(fā)送的內(nèi)容通常是由支持“流式傳輸”結(jié)果的“某物”生成的。一個示例可能是從結(jié)構(gòu)或映射生成的 JSON 響應。
在這種情況下,如果它支持將結(jié)果寫入即時消息http.ResponseWriter,則傳遞/移交您的內(nèi)容通常會更有效。io.Writerio.Writer
一個很好的例子是生成 JSON 響應。當然,您可以使用 將一個對象編組為 JSON json.Marshal(),它會返回一個字節(jié)切片,您可以通過調(diào)用簡單地發(fā)送它ResponseWriter.Write()。
然而,讓json包知道你有一個io.Writer,并且最終你想將結(jié)果發(fā)送給它會更有效。這樣就不必首先在緩沖區(qū)中生成 JSON 文本,您只需將其寫入響應然后丟棄。json.Encoder您可以通過調(diào)用來創(chuàng)建一個新的json.NewEncoder(),您可以將您的http.ResponseWriteras傳遞給它io.Writer,然后調(diào)用Encoder.Encode()將直接將 JSON 結(jié)果寫入您的響應編寫器。
這里的一個缺點是,如果生成 JSON 響應失敗,您可能會收到部分發(fā)送/提交的響應,您無法收回。如果這對您來說是個問題,那么您除了在緩沖區(qū)中生成響應之外別無選擇,如果封送處理成功,那么您可以立即編寫完整的響應。

TA貢獻1828條經(jīng)驗 獲得超13個贊
從這里(ResponseWriter)可以看出,它是一個帶有Write([]byte) (int, error)方法的接口。
所以 inio.WriteString和fmt.Fprintf兩者都將Writer作為第一個參數(shù),這也是一種接口包裝Write(p []byte) (n int, err error)方法
type Writer interface {
Write(p []byte) (n int, err error)
}
因此,當您調(diào)用 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))
}
或 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
}
您只是ResponseWriter在兩種方法中傳遞變量時間接調(diào)用 Write Method。
所以為什么不直接使用w.Write([]byte("blabla\n")). 我希望你得到你的答案。
PS:如果您想將其作為 JSON 響應發(fā)送,還有一種不同的使用方式。
json.NewEncoder(w).Encode(wrapper)
//Encode take interface as an argument. Wrapper can be:
//wrapper := SuccessResponseWrapper{Success:true, Data:data}
- 2 回答
- 0 關注
- 648 瀏覽
添加回答
舉報