ReadOnlySpan<char> r = someString.AsSpan();
string newStr = new string(span); 或使用 string.Create(length, state, spanAction) 以避免額外中間分配的多次拷貝。MemoryMarshal.AsBytes<T>(span) 將 Span<T> 轉為 Span<byte>(注意對齊與相依型別安全性)。Encoding.UTF8.GetBytes(ReadOnlySpan<char> chars, Span<byte> bytes) 與 Encoding.UTF8.GetString(ReadOnlySpan<byte> bytes)。像是以下例子,想要高效率 UTF-8 編碼到預先分配的 buffer
using System;
using System.Text;
Span<byte> outBuf = stackalloc byte[128];
ReadOnlySpan<char> text = "Hello 世界".AsSpan();
int written = Encoding.UTF8.GetBytes(text, outBuf);
// 現在 outBuf.Slice(0, written) 包含 UTF-8 bytes
要注意
Span<T> 放到類的欄位或用作 async/await 中的局部變數會導致編譯錯誤或不可預期的行為,編譯器會阻止這些用法。stackalloc 或來自非托管記憶體的 Span<T> 時要注意生命週期,千萬不要將資料引用回傳給呼叫端。若要回傳,可考慮 Memory<T> 搭配 MemoryPool。Memory<T>.Pin() 與 MemoryMarshal.GetReference() 可以在需要 pin 時使用,但務必在 fixed 或受控區塊內使用以避免 GC moving 導致的問題。建議
Span<T> 來避免分配。若操作必須跨越非同步邊界,使用 Memory<T> + IMemoryOwner<T>(MemoryPool)。Substring 在熱路徑建立大量臨時字串,改用 ReadOnlySpan<char>。Encoding 的 span-overloads 以避免中間陣列。像是我們可以用 Span 實作簡單的 CSV 欄位拆分,能達到同步、無分配
using System;
void PrintCsvFields(ReadOnlySpan<char> line)
{
while (!line.IsEmpty)
{
int idx = line.IndexOf(',');
if (idx == -1)
{
Console.WriteLine(line.ToString());
break;
}
var field = line.Slice(0, idx);
Console.WriteLine(field.ToString());
line = line.Slice(idx + 1);
}
}
PrintCsvFields("a,b,c,d".AsSpan());
在微軟設計中,字串提供了方便且不可變的字元序列表現,Span<T> 提供低延遲、零分配的同步操作視圖;Memory<T> 則是在需要可傳遞、長期保留或跨 async 邊界時的安全選擇。