4 回答

TA貢獻1831條經(jīng)驗 獲得超9個贊
Go 中的字符串一旦創(chuàng)建就不可變。去規(guī)范
我會更喜歡下面的builder。您繼續(xù)添加到構(gòu)建器的緩沖區(qū)(可變)WriteString 并且一旦完成調(diào)用String返回指針而不是緩沖區(qū)切片的另一個副本的方法。
somestring := "Hello Go"
var sb strings.Builder
if _, err := sb.WriteString(somestring); err != nil {
//log & return
}
newstring := sb.String()
從 go 源碼檢查 builder 的 String() 的實現(xiàn)。它返回指針并轉(zhuǎn)換為 *string。沒有第二份。
// String returns the accumulated string.
func (b *Builder) String() string {
return *(*string)(unsafe.Pointer(&b.buf))
}

TA貢獻1828條經(jīng)驗 獲得超13個贊
另一種選擇是,從 go 1.18(2021 年第四季度)開始:
sCopy := strings.Clone(s)
它來自問題40200和45038,并從 CL(更改列表)334884和345849 開始
字節(jié),字符串:添加克隆
直接使用
[]byte
并且string
很常見并且需要經(jīng)常復制它們。
此更改Clone
為字符串和字節(jié)添加了一個助手來滿足此需求。
還添加了一個基準,以提供證據(jù)說明為什么bytes.Clone
使用copy
.字符串:添加克隆功能
新
strings.Clone
函數(shù)復制輸入字符串,但返回的克隆字符串不引用輸入字符串內(nèi)存
// Clone returns a fresh copy of s.
//
// It guarantees to make a copy of s into a new allocation,
// which can be important when retaining only a small substring
// of a much larger string. Using Clone can help such programs
// use less memory.
//
// Of course, since using Clone makes a copy,
// overuse of Clone can make programs use more memory.
//
// Clone should typically be used only rarely, and only when
// profiling indicates that it is needed.
//
func Clone(s string) string {
b := make([]byte, len(s))
copy(b, s)
return *(*string)(unsafe.Pointer(&b))
}

TA貢獻1842條經(jīng)驗 獲得超13個贊
字符串被實現(xiàn)為指向底層字節(jié)數(shù)組和字符串長度的指針。當您從現(xiàn)有字符串創(chuàng)建切片時,新字符串仍指向基礎(chǔ)數(shù)組,可能指向該數(shù)組中具有不同長度的不同偏移量。這樣,許多小字符串可以使用單個底層大數(shù)組。
正如您所指出的,如果您有一個大字符串并將其解析為較小的字符串,那么您最終會將大字符串保留在內(nèi)存中,因為 GC 只知道底層數(shù)組和指向它的指針。有兩種方法可以處理這個問題:
不要使用大字符串,而是保留
[]byte
或使用基于字節(jié)流的讀取器/掃描器,并在解析時從輸入創(chuàng)建字符串。這樣 GC 將[]byte
在解析完成時收集底層,并且您將擁有沒有底層大塊的字符串。執(zhí)行您已經(jīng)描述的操作,并使用
string([]byte(s[x:y]))
或使用copy
.

TA貢獻1744條經(jīng)驗 獲得超4個贊
使用以下函數(shù)深度復制字符串:
func deepCopy(s string) string {
b := make([]byte, len(s))
copy(b, s)
return *(*string)(unsafe.Pointer(&b))
}
該函數(shù)將數(shù)據(jù)復制到新分配的字節(jié)片中。該函數(shù)使用 unsafe 包將切片標頭轉(zhuǎn)換為不復制字節(jié)的字符串標頭。
如果直接使用 unsafe 包是一個問題,那么使用strings.Builder。strings.Builder 類型在幕后執(zhí)行不安全的惡作劇。
func deepCopy(s string) string {
var sb strings.Builder
sb.WriteString(s)
return sb.String()
}
無需檢查 sb.WriteString 返回的錯誤。Builder.WriteString方法有錯誤返回,所以 Builder 類型滿足 io.StringWriter接口,而不是因為 WriteString 可以返回非 nil 錯誤。
- 4 回答
- 0 關(guān)注
- 189 瀏覽
添加回答
舉報