我正在嘗試實(shí)現(xiàn)一個(gè)滿足 io.Writer 要求的代理,因此我可以將其插入記錄器。這個(gè)想法是它會(huì)像平常一樣打印輸出,但也會(huì)保留一份數(shù)據(jù)副本供以后讀取。以下代碼中的 ProxyIO 結(jié)構(gòu)應(yīng)該執(zhí)行此操作,而且只要我直接調(diào)用其 Write() 方法,它確實(shí)會(huì)執(zhí)行此操作。但是,當(dāng)我將它插入 log.Logger 實(shí)例時(shí),輸出是意外的。(這是精簡(jiǎn)代碼,我想使用的原始實(shí)現(xiàn)是使用映射和循環(huán)指針,而不是[][]byte示例代碼中使用的 buf。我還刪除了所有鎖定。)package mainimport ( "fmt" "io" "io/ioutil" "log")type ProxyIO struct { out io.Writer // the io we are proxying buf [][]byte}func newProxyIO(out io.Writer) *ProxyIO { return &ProxyIO{ out: out, buf: [][]byte{}, }}func (r *ProxyIO) Write(s []byte) (int, error) { r.out.Write(s) r.buf = append(r.buf, s) return len(s), nil}func main() { p := newProxyIO(ioutil.Discard) p.Write([]byte("test1\n")) p.Write([]byte("test2\n")) p.Write([]byte("test3\n")) l := log.New(p, "", 0) l.Print("test4") l.Print("test5") l.Print("test6") for i, e := range p.buf { fmt.Printf("%d: %s", i, e) }}(這里是操場(chǎng)上的代碼https://play.golang.org/p/UoOq4Nd-rmI)我希望這段代碼有以下輸出:0: test11: test22: test33: test44: test55: test6但是,它將始終打?。?: test11: test22: test33: test64: test65: test6我的地圖實(shí)現(xiàn)的行為是相同的。我還嘗試使用雙向鏈表作為container/list存儲(chǔ),它總是一樣的。所以我一定在這里遺漏了一些重要的東西。為什么我在緩沖區(qū)中看到了三次最后的日志輸出,而不是最后三行日志輸出?
1 回答

catspeake
TA貢獻(xiàn)1111條經(jīng)驗(yàn) 獲得超0個(gè)贊
如果您查看源代碼,Logger.Print
您會(huì)看到它調(diào)用logger.Output
.?您會(huì)注意到它如何將字符串的值設(shè)置為l.buf
然后調(diào)用Write
您會(huì)發(fā)現(xiàn)即使所有內(nèi)容都是按值傳遞的
當(dāng)您將切片傳遞給函數(shù)時(shí),將從該標(biāo)頭制作一個(gè)副本,包括指針,該指針將指向相同的后備數(shù)組。
所以當(dāng)你這樣做時(shí):
l.Print("test4") l.Print("test5") l.Print("test6")
Logger 有效地重復(fù)使用同一個(gè)切片,并且您正在append
對(duì)同一個(gè)切片引用 3 次,因此在打印時(shí)自然會(huì)使用 3 次最新的值集。
[]byte
要解決此問題,您可以像這樣在使用之前復(fù)制:
func?(r?*ProxyIO)?Write(s?[]byte)?(int,?error)?{ ????c?:=?make([]byte,?len(s)) ????????copy(c,?s) ????r.out.Write(c) ????r.buf?=?append(r.buf,?c) ????????return?len(c),?nil}
- 1 回答
- 0 關(guān)注
- 182 瀏覽
添加回答
舉報(bào)
0/150
提交
取消