解读 --- Span<T>
引言
Span<T>
是C# 中的一种结构体,它是一种内存安全的类型,可以用来表示连续的内存区域。Span<T>
可以被用于访问和操作数组、堆上分配的内存和栈上分配的内存。使用 Span<T>
可以避免不必要的内存拷贝,从而提高性能。
对数组使用Span
如果需要快速访问托管或非托管的连续内存,可以使用 Span<T>
结构。Span<T>
结构表示存储连续的内存。所以使用它的数据结构一般也使用连续的内存。例如:
- 数组
- 长字符串(实际上也是数组)
使用 Span<T>
,可以直接访问数组元素。且数组的元素不会复制,可以直接使用它们,这样比复制效率要高。例如下面的代码:
static void Main(string[] args)
{
int[] source = new int[] { 1, 2, 3 };
int[] arr = new int[] { source[0], source[1], source[2] };
arr[0] = 33;
Console.WriteLine($"The first element of source is {source[0]}");
Console.WriteLine($"The first element of arr is {arr[0]}");
Span<int> span = new(source);
span[0] = 11;
Console.WriteLine($"The first element of source is {arr[0]}");
Console.WriteLine($"The first element of span is {span[0]}");
Console.ReadLine();
}
可以先猜测以下上述代码的输出是什么?
输出:
The first element of source is 1
The first element of arr is 33
The first element of source is 11
The first element of span is 11
上述代码段中,先声明了一个源数组 source
和一个数组 arr
,并将 source
的值复制给 arr
。然后修改 arr
中的第一个元素值为33,可以看到结果 arr
的第一个元素已经改变为33,source
保持不变。然后又声明了一个 Span<int>
,它引用 source
数组。因为Span<T>
是直接访问数组元素,而不是复制元素,所以修改 span
中的第一个元素为11, source
中的第一个元素也被修改为11。
创建切片
Span<T>
的一个强大特性是,可以使用它访问数组的部分或切片。使用切片时,不会复制数组元素,它们是从span 中直接访问的。
有如下代码段:
static void Main(string[] args)
{
int[] source = { 1, 6, 23, 76, 88, 213 };
Span<int> span1 = new Span<int>(source, start: 1, length: 4);
Span<int> span2 = span1.Slice(start: 1, length: 3);
DisplaySpan("span1 contains the elements:", span1);
DisplaySpan("span2 contains the elements:", span2);
Console.ReadLine();
}
private static void DisplaySpan(string content, Span<int> span1)
{
Console.Write(content);
foreach (var item in span1)
{
Console.Write(item + ",");
}
Console.WriteLine();
}
下面的代码片段展示了创建切片的两种方法。
- 除默认构造函数传参数组之外,另一种重载是直接使用构造函数传递源数组,起始位置和长度。例如上述代码中
new Span<int>(source, start: 1, length: 4)
它表示在源数组中从第2个元素开始访问数组的4个元素。 - 直接从span中再次切片,传入起始位置和长度,例如上述代码中
span1.Slice(start: 1, length: 3)
表示从span1中第2个元素开始包含3个元素的切片。
输出:
span1 contains the elements:6,23,76,88,
span2 contains the elements: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>
,如下:
static void Main(string[] args)
{
int[] source = { 1, 6, 23, 76, 88, 213 };
Span<int> span = new Span<int>(source);
DisplaySpan("span contains the elements:", span);
ReadOnlySpan<int> readOnlySpan = source;
DisplaySpan("readOnlySpan contains the elements:", readOnlySpan);
Console.ReadLine();
}
private static void DisplaySpan(string content, ReadOnlySpan<int> span1)
{
Console.Write(content);
foreach (var item in span1)
{
Console.Write(item + ",");
}
Console.WriteLine();
}
输出:
span contains the elements:1,6,23,76,88,213,
readOnlySpan contains the elements:1,6,23,76,88,213,
与 Span<T>
相比,ReadOnlySpan<T>
的一个重要的限制是不允许修改其包含的内存块。这使得 ReadOnlySpan<T>
更适合于读取内存块中的数据,而不是修改它们。
解读 --- Span<T>的更多相关文章
- C# Span 源码解读和应用实践
一:背景 1. 讲故事 这两天工作上太忙没有及时持续的文章产出,和大家说声抱歉,前几天群里一个朋友在问什么时候可以产出 Span 的下一篇,哈哈,这就来啦!读过上一篇的朋友应该都知道 Span 统一了 ...
- 解读ASP.NET 5 & MVC6系列(13):TagHelper
在新版的MVC6中,微软提供了强大的TagHelper功能,以便让我们摆脱如下的臃肿代码: @Html.LabelFor(model => model.FullName) @Html.EditF ...
- 解读ASP.NET 5 & MVC6系列(1):ASP.NET 5简介
ASP.NET 5简介 ASP.NET 5是一个跨时代的改写,所有的功能和模块都进行了独立拆分,做到了彻底解耦.为了这些改写,微软也是蛮 拼的,几乎把.NET Framwrok全部改写了一遍,形成了一 ...
- 优秀开源代码解读之JS与iOS Native Code互调的优雅实现方案
简介 本篇为大家介绍一个优秀的开源小项目:WebViewJavascriptBridge. 它优雅地实现了在使用UIWebView时JS与ios 的ObjC nativecode之间的互调,支持消息发 ...
- Hybrid----优秀开源代码解读之JS与iOS Native Code互调的优雅实现方案-备
本篇为大家介绍一个优秀的开源小项目:WebViewJavascriptBridge. 它优雅地实现了在使用UIWebView时JS与ios 的ObjC nativecode之间的互调,支持消息发送.接 ...
- Jsoup代码解读之六-防御XSS攻击
Jsoup代码解读之八-防御XSS攻击 防御XSS攻击的一般原理 cleaner是Jsoup的重要功能之一,我们常用它来进行富文本输入中的XSS防御. 我们知道,XSS攻击的一般方式是,通过在页面输入 ...
- Jsoup代码解读之三-Document的输出
Jsoup代码解读之三-Document的输出 Jsoup官方说明里,一个重要的功能就是output tidy HTML.这里我们看看Jsoup是如何输出HTML的. HTML相关知识 分析代码前 ...
- CSS之float属性解读
在web标准的网页中,页面各个元素都是以标准流的方式来进行布局的.即块元素占满指定的宽度,不指定宽度则占满整行(如<p>.<div>元素),内联元素则是在行内一个接一个的从左到 ...
- Angularjs directive全面解读(1.4.5)
说到Angularjs directive即指令,可以这么说Angularjs的灵魂就是指令,学会Angularjs指令那么你的Angularjs的武功就修炼了一半了,当然这只是鄙人的一点点独到见解, ...
- 唱吧DevOps的落地,微服务CI/CD的范本技术解读----最大的难点并不是实际业务代码的编写,而是服务的监控和调试以及容器的编排
1.业务架构:从单体式到微服务 K歌亭是唱吧的一条新业务线,旨在提供线下便捷的快餐式K歌方式,用户可以在一个电话亭大小的空间里完成K歌体验.K歌亭在客户端有VOD.微信和Web共三个交互入口,业务复杂 ...
随机推荐
- 2022-11-17:组合两个表。请写出sql语句,执行结果是{“headers“: [“first_name“, “last_name“, “city“, “state“], “values“: [
2022-11-17:组合两个表.请写出sql语句,执行结果是{"headers": ["first_name", "last_name", ...
- 2020-11-26:go中,map的创建流程是什么?
福哥答案2020-11-26: [答案来自此链接:](https://www.bilibili.com/video/BV1Nr4y1w7aa?p=10)源码位于runtime/map.go文件中的ma ...
- 2022-01-24:K 距离间隔重排字符串。 给你一个非空的字符串 s 和一个整数 k,你要将这个字符串中的字母进行重新排列,使得重排后的字符串中相同字母的位置间隔距离至少为 k。 所有输入的字符串
2022-01-24:K 距离间隔重排字符串. 给你一个非空的字符串 s 和一个整数 k,你要将这个字符串中的字母进行重新排列,使得重排后的字符串中相同字母的位置间隔距离至少为 k. 所有输入的字符串 ...
- windows10 docker desktop与本机数据拷贝
目录 前景提示 一.构建环境 二.安装测试需要的nginx 三. docker文件拷贝到windows本地 总结 前景提示 发现只有docker关于docker拷贝linux内部文件的命令,但是,对于 ...
- ITIL介绍
摘自:金角大王 https://www.cnblogs.com/alex3714/articles/5420433.html 本节内容 浅谈ITIL CMDB介绍 Django自定义用户认证 Rest ...
- es笔记一之es安装与介绍
本文首发于公众号:Hunter后端 原文链接:es笔记一之es安装与介绍 首先介绍一下 es,全名为 Elasticsearch,它定义上不是一种数据库,是一种搜索引擎. 我们可以把海量数据都放到 e ...
- 洛谷P3368 【模板】树状数组 2-(区间修改,单点查询)
题目描述 如题,已知一个数列,你需要进行下面两种操作: 将某区间每一个数加上 x: 求出某一个数的值. 输入格式 第一行包含两个整数 N.M,分别表示该数列数字的个数和操作的总个数. 第二行包含 N ...
- js原型和原型链(用代码理解代码)
众所周知js原型及原型链是很多开发者的一个疼点(我也不例外),我也曾多次被问起,也问过不少其他人,如果在自己没有真正的去实践和理解过:那么突然之间要去用最简单的话语进行概述还真不是一件容易的事情: 其 ...
- 值得推荐的Blazor UI组件库
前言 本文主要是推荐一些开源.免费.实用.美观的Blazor UI组件库,提供给广大C#/.NET开发者们学习和使用(注意:排名不分先后,都是十分优秀的开源框架和项目).本文中的所有框架都已经收录到适 ...
- 【RS】多光谱波段和全色波段的区别
<p><strong>1.全色波段(Panchromatic Band)</strong></p> 全色图像是单通道的(即单波段灰色影像),其中全色是指 ...