てくメモ

trivial な notes

【C#】Span の分解

Spanの分解について。


本題の前に、スライシングに触れる。
とても快適だと思う。

// ReadOnlySpan<char> span;

var s1 = span.Slice(1); // Slice メソッド
var s2 = span[1..]; // 範囲演算子

var s3 = span.Slice(1, 3); // 長さで切るときは Slice の方がわかりやすい
var endIndex = span.IndexOf('。');
var s4 = span[1..endIndex]; // インデックスなら範囲演算子が直感的

var s5 = span[..^1]; // ^演算子で末尾を落としたりも。LINQのSkipLast(1)
var s6 = span[^2..]; // TakeLast(2)


それでは分解。

要素に触れるためには、素直にやればインデックスアクセス。

var (a, b, c) = (span[0], span[1], span[2]); 

少し大変な感じがある。

[ ]という記号はスライシングの範囲構文と同じはずなのに、インデックスアクセスとなると重く感じる。
スライシングと較べると快適とは言いづらい。


C# 11.0 ではリストパターンが登場し、パターンマッチングの文脈で以下のような感じに変数宣言できる。

// 意味のない if 文だけれど例示ということで...
if (span is [var first, var second, ..var rest]) {} // 残り全部を表現する範囲演算子
if (span is [_, _, var target]) {} // 範囲演算子無しでは要素数は決めうち(違うとマッチしない)

ただ、あくまでパターンマッチングでの記法なため次のようには使えない。

[var a, var b, var c] = span; // できない😥


パターンマッチング以外の文脈でインデックスアクセスが気に入らない場合、Deconstructメソッドを用意し分解をすることができる。
拡張メソッドも含めDeconstructを持つ型は、ValueTupleで分解可能。

public static void Deconstruct<T>(this ReadOnlySpan<T> span, out T item1, out T item2, out T item3)
{
    item1 = span[0];
    item2 = span[1];
    item3 = span[2];
}
var (a, b, c) = span;

😊


以下はコピペ用Span, ReadOnlySpanDeconstruct

長いので折りたたみ

public static void Deconstruct<T>(this Span<T> span, out T item1, out T item2)
{
    item1 = span[0];
    item2 = span[1];
}
public static void Deconstruct<T>(this Span<T> span, out T item1, out T item2, out T item3)
{
    item1 = span[0];
    item2 = span[1];
    item3 = span[2];
}
public static void Deconstruct<T>(this Span<T> span, out T item1, out T item2, out T item3, out T item4)
{
    item1 = span[0];
    item2 = span[1];
    item3 = span[2];
    item4 = span[3];
}
public static void Deconstruct<T>(this Span<T> span, out T item1, out T item2, out T item3, out T item4, out T item5)
{
    item1 = span[0];
    item2 = span[1];
    item3 = span[2];
    item4 = span[3];
    item5 = span[4];
}
public static void Deconstruct<T>(this Span<T> span, out T item1, out T item2, out T item3, out T item4, out T item5, out T item6)
{
    item1 = span[0];
    item2 = span[1];
    item3 = span[2];
    item4 = span[3];
    item5 = span[4];
    item6 = span[5];
}
public static void Deconstruct<T>(this Span<T> span, out T item1, out T item2, out T item3, out T item4, out T item5, out T item6, out T item7)
{
    item1 = span[0];
    item2 = span[1];
    item3 = span[2];
    item4 = span[3];
    item5 = span[4];
    item6 = span[5];
    item7 = span[6];
}
public static void Deconstruct<T>(this Span<T> span, out T item1, out T item2, out T item3, out T item4, out T item5, out T item6, out T item7, out T item8)
{
    item1 = span[0];
    item2 = span[1];
    item3 = span[2];
    item4 = span[3];
    item5 = span[4];
    item6 = span[5];
    item7 = span[6];
    item8 = span[7];
}

public static void Deconstruct<T>(this ReadOnlySpan<T> span, out T item1, out T item2)
{
    item1 = span[0];
    item2 = span[1];
}
public static void Deconstruct<T>(this ReadOnlySpan<T> span, out T item1, out T item2, out T item3)
{
    item1 = span[0];
    item2 = span[1];
    item3 = span[2];
}
public static void Deconstruct<T>(this ReadOnlySpan<T> span, out T item1, out T item2, out T item3, out T item4)
{
    item1 = span[0];
    item2 = span[1];
    item3 = span[2];
    item4 = span[3];
}
public static void Deconstruct<T>(this ReadOnlySpan<T> span, out T item1, out T item2, out T item3, out T item4, out T item5)
{
    item1 = span[0];
    item2 = span[1];
    item3 = span[2];
    item4 = span[3];
    item5 = span[4];
}
public static void Deconstruct<T>(this ReadOnlySpan<T> span, out T item1, out T item2, out T item3, out T item4, out T item5, out T item6)
{
    item1 = span[0];
    item2 = span[1];
    item3 = span[2];
    item4 = span[3];
    item5 = span[4];
    item6 = span[5];
}
public static void Deconstruct<T>(this ReadOnlySpan<T> span, out T item1, out T item2, out T item3, out T item4, out T item5, out T item6, out T item7)
{
    item1 = span[0];
    item2 = span[1];
    item3 = span[2];
    item4 = span[3];
    item5 = span[4];
    item6 = span[5];
    item7 = span[6];
}
public static void Deconstruct<T>(this ReadOnlySpan<T> span, out T item1, out T item2, out T item3, out T item4, out T item5, out T item6, out T item7, out T item8)
{
    item1 = span[0];
    item2 = span[1];
    item3 = span[2];
    item4 = span[3];
    item5 = span[4];
    item6 = span[5];
    item7 = span[6];
    item8 = span[7];
}