解读 --- Span<T>

解读 --- Span<T>
Fantasy-ke引言
Span 是C# 中的一种结构体,它是一种内存安全的类型,可以用来表示连续的内存区域。Span 可以被用于访问和操作数组、堆上分配的内存和栈上分配的内存。使用 Span 可以避免不必要的内存拷贝,从而提高性能。
引言
Span<T> 是C# 中的一种结构体,它是一种内存安全的类型,可以用来表示连续的内存区域。Span<T> 可以被用于访问和操作数组、堆上分配的内存和栈上分配的内存。使用 Span<T> 可以避免不必要的内存拷贝,从而提高性能。
对数组使用Span
如果需要快速访问托管或非托管的连续内存,可以使用 Span<T>结构。Span<T> 结构表示存储连续的内存。所以使用它的数据结构一般也使用连续的内存。例如:
- 数组
- 长字符串(实际上也是数组)
使用 Span<T>,可以直接访问数组元素。且数组的元素不会复制,可以直接使用它们,这样比复制效率要高。例如下面的代码:
1 | static void Main(string[] args) |
可以先猜测以下上述代码的输出是什么?
输出:
1 | is 1 |
上述代码段中,先声明了一个源数组 source 和一个数组 arr ,并将 source 的值复制给 arr 。然后修改 arr 中的第一个元素值为33,可以看到结果 arr 的第一个元素已经改变为33,source 保持不变。然后又声明了一个 Span<int> ,它引用 source 数组。因为Span<T>是直接访问数组元素,而不是复制元素,所以修改 span 中的第一个元素为11, source 中的第一个元素也被修改为11。
创建切片
Span<T> 的一个强大特性是,可以使用它访问数组的部分或切片。使用切片时,不会复制数组元素,它们是从span 中直接访问的。
有如下代码段:
1 | static void Main(string[] args) |
下面的代码片段展示了创建切片的两种方法。
- 除默认构造函数传参数组之外,另一种重载是直接使用构造函数传递源数组,起始位置和长度。例如上述代码中
new Span<int>(source, start: 1, length: 4)它表示在源数组中从第2个元素开始访问数组的4个元素。 - 直接从span中再次切片,传入起始位置和长度,例如上述代码中
span1.Slice(start: 1, length: 3)表示从span1中第2个元素开始包含3个元素的切片。
输出:
1 | 6,23,76,88, |
这里使用时一定注意传入参数 start 和 length 后的越界问题。
使用Span改变值
在文章开头,介绍了如何使用 Span<T> 的索引器,直接更改由 span 直接引用的数组元素,实际上它还有其他改变值的方法。
例如:
Slice(int start, int length):返回一个新的Span<T>,它表示从Span<T>的指定起始位置开始的指定长度部分。可以使用该方法来获取或更改Span<T>中的子集。Clear():将Span<T>中的所有元素设置为默认值default<T>。Fill(T value):将Span<T>中的所有元素设置为指定的值。CopyTo(Span<T> destination):将Span<T>中的所有元素复制到指定的目标Span<T>。CopyTo(T[] destination):将Span<T>中的所有元素复制到指定的目标数组。Reverse():反转Span<T>中的元素顺序。Sort():对Span<T>中的元素进行排序。
请注意,这些方法都是按值传递的,而不是按引用传递的。这意味着在调用这些方法时,将复制 Span<T> 中的值。如果您想要修改原始 Span<T> 中的值,请使用引用传递方式,例如使用 ref Span<T> 参数。
只读的Span
如果只需要对数组片段进行读访问,则可以使用 ReadOnlySpan<T>,可以使用它来读取内存块中的数据,而不必担心其他代码同时修改了该内存块。
对于 ReadOnlySpan<T> ,它的索引器是只读的,所以这种类型没有提供 Clear 和 Fill 方法,但是可以调用 CopyTo() 方法,将 ReadOnlySpan<T> 的内容复制到 Span<T> 。
此外,它支持隐式转换,由数组或 Span<T> 直接赋值给 ReadOnlySpan<T>,如下:
1 | static void Main(string[] args) |
输出:
1 | 1,6,23,76,88,213, |
与 Span<T> 相比,ReadOnlySpan<T> 的一个重要的限制是不允许修改其包含的内存块。这使得 ReadOnlySpan<T> 更适合于读取内存块中的数据,而不是修改它们。









