O que é Span<T>

você lembra dos tipos por valor?

Wilson Santos
3 min readMar 5, 2021

É um novo tipo por valor no coração do .net que permite a representação continua de espaços de memoria, foi mais ou menos isso que o Stephen Toub disse sobre esse recurso no msdn.

Se você ainda não sabe o que é heap e stack de uma olhadinha aqui

Essa frase simples significa;

  1. é um tipo nativo que não vai ser gerenciado
  2. é um tipo que fica alocado na Stack
  3. tem alta performance
  4. evita o uso de código “unsafe”.

Pense nisso como ter um array para acessar a memória bruta. Vamos fazer um exemplo simples com um array de bytes para entender como acessar a memoria.

var arr = new byte[10];
Span<byte> bytes = arr;
bytes[0] = 42;
Console.WriteLine($"arr:{arr[0]},bytes:{bytes[0]}");

Agora vamos pegar um parte do array e manipula-lo

Span<byte> slices = bytes.Slice(4,3);
slices[0] = 43;
Console.WriteLine($"arr:{arr[4]},bytes:{bytes[4]}");

Agora quando manipulamos um string podemos entender um pouco por que esse recurso é tão bom para saúde das nossas aplicações.

string teste = "WiL171";
teste = teste.Substring(3);
int num = int.Parse(teste);
Console.WriteLine(num);
percebam que usamos o endereço 0x02 mas o endereço 0x01 esta sem referencia e por isso o GC vai ser acionado. Alem de termos o valor duplicado na heap e na Stack

Com o Span fica assim;

string teste = "WiL171";
ReadOnlySpan<char> s = teste.AsSpan();
s = s.Slice(3);
int num = int.Parse(s);
Console.WriteLine(num);
Assim não tem duplicidade e não tem GC

mas os caras ainda deram uma melhorada e .net core a estrutura ficou assim;

Outros exemplos que podem melhorar o uso de memoria.

Isso;

public static bool ContainsCapitalLetters(string s)
{
for (int i = 0; i < s.Length; i++)
{
if (char.IsUpper(s[i]))
return true;
}
return false;
}

Pra isso;

public static bool ContainsCapitalLetters(ReadOnlySpan<char> s)
{
for (int i = 0; i < s.Length; i++)
{
if (char.IsUpper(s[i]))
return true;
}
return false;
}

ou isso;

public static int Sum(int[] a)
{
int sum = 0;
for (int i = 0; i < a.Length; i++)
{
sum += a[i];
}
return sum;
}

para isso;

public static int Sum(ReadOnlySpan<int> a)
{
int sum = 0;
for (int i = 0; i < a.Length; i++)
{
sum += a[i];
}
return sum;
}

Observe que sempre que vamos usar o span<T> temos esse cara ReadOnlySpan para nos auxiliar, ele tipa uma variável com uma estrutura que nunca vai ser alocada na HEAP e para isso existem muitas restrições quanto ao uso desses tipos.

Por Exemplo, não podemos fazer boxing com eles , não podem ser usados em tipos dinâmicos, nem em expressões lambdas, não podemos usa-los em interfaces, tudo isso para garantir que ele nunca escape para a HEAP.

Referencia

  1. Sobre Span: Explorando um Novo Suporte do .NET
  2. A (brief) overview of Span≤T≥ — David Wengier
  3. https://adamsitnik.com/Span/

--

--

Wilson Santos

Nos últimos 15 anos, venho desenvolvendo , aperfeiçoando e integrando sistemas, sou apaixonado por desenvolver e ensinar, nem tanto por escrever!.