次の方法で共有


18 拡張インデックス作成とスライス

18.1 全般

この句では、次に基づいて構築 された拡張インデックス可能 コレクション型と スライサーブルコレクション 型のモデルが導入されています。

  • この句で導入された型、 System.Index (§18.2) と System.Range (§18.3);
  • 定義済みの単項 ^ (§12.9.6) および二項 .. (§12.10) 演算子。
  • element_access式。

モデルでは、型は次のように分類されます。

  • 要素s のグループを表す場合はコレクション
  • 型の単一の引数式を持つelement_access式をサポートする場合は、Indexコレクション。値または参照によって型の単一の要素を返したり設定したりします。
  • 型の単一の引数式を持つelement_access式をサポートする場合は、値によって型の要素のスライスを返すRange拡張スライサーブル コレクション。

: モデルでは、型のスライスを設定できる必要はありませんが、型でモデルの拡張機能としてサポートされる場合があります。 注釈

このモデルは、1 次元配列 (§12.8.12.2) と文字列 (§12.8.12.3) でサポートされています。

モデルは、モデル セマンティクスを実装する適切なインデクサー (§15.9) を提供する任意のクラス、構造体、またはインターフェイス型でサポートできます。

モデルの暗黙的なサポートは、モデルを直接サポートせず、メンバーの特定の パターン を提供する型 (§18.4) に対して提供されます。 このサポートは、ベースとなる型メンバーのセマンティクスが 想定 されるため、セマンティック ベースではなくパターンベースです。言語では、これらの型メンバーのセマンティクスは強制またはチェックされません。

この句の目的上、次の用語が定義されています。

  • コレクションは、要素s のグループを表す型です。
  • カウント可能なコレクションは、現在グループ内の要素の数を値とする値を持つインスタンス プロパティをに提供するものです。 このプロパティには、 Length または Countのいずれかの名前を付ける必要があります。 両方が存在する場合は、前者が選択されます。
  • シーケンスまたはインデックス可能な型はコレクションです。
    • これはカウント可能です。
    • 1 つの必須引数、int、追加の省略可能な引数を持つelement_access式を使用して、すべての要素にアクセスできます。
    • element_access式を使用してすべての要素を設定できる場合、シーケンスは変更可能です。
    • 要素の開始位置インデックスは、 N 個の要素を含むシーケンスに対する、シーケンス内の要素の前の要素の数です。
      • 最初の要素と最後の要素はそれぞれ 0 と N-1 のインデックスを持ち、
      • 最後のインデックスの後の仮定の要素を表すインデックスである 、過去のインデックスには値 N があります。
  • From-end インデックスは、過去のインデックスを基準にしたシーケンス内での要素の位置を表します。 N 個の要素を含むシーケンスの場合、最後と最後のインデックスはそれぞれ N、1、0 です。
  • 範囲は、シーケンス内の任意のインデックスから始まる 0 個以上のインデックスの連続した実行です。
  • スライスは、範囲内の要素のコレクションです。
  • スライス可能なコレクションは、次のいずれかです。
    • はカウント可能です。
    • には、範囲を指定する 2 つのSlice パラメーター (開始インデックスと要素の数) を受け取り、範囲内の要素から構築された新しいスライスを返すメソッド intが用意されています。

上記の定義は、次のように IndexRange の使用のために拡張されています。

  • 引数ではなく、1 つの必須引数を受け取るelement_access式がサポートされている場合、型もIndexです。 区別が必要な場合、型は 拡張インデックス可能と呼びます。
  • 型は、 メソッドではなく、1 つの必須Range引数を受け取るelement_access式がサポートされている場合にもSliceです。 区別が必要な場合、型は 拡張スライサーブルと呼ばれる。

型がカウント可能、インデックス付き、またはスライス可能として分類されるかどうかは、メンバー のアクセシビリティ (§7.5) の制約の対象となるため、型が使用されている場所によって異なります。

: カウント可能なプロパティやインデクサーが protected される型は、それ自体および派生型のメンバーに対するシーケンスにすぎません。 終了サンプル

シーケンスまたはスライサーブルとして修飾する型に必要なメンバーを継承できます。

: 次のコード内

public class A
{
    public int Length { get { … } }
}

public class B : A
{
    public int this(int index) { … }
}

public class C : B
{
    public int[] Slice(int index, int count) { … }
}

A型はカウント可能であり、Bはシーケンスであり、Cはスライス可能でシーケンスです。

終了サンプル

Note:

  • (アクセス可能な) インデクサーがないため、型はインデックスを作成せずにスライスできます。
  • 型をスライス可能またはインデックス可能にするには、型をカウント可能にする必要があります。
  • シーケンスの要素はシーケンス内の 位置 で並べ替えられるが、要素自体は値で並べ替える必要も、順序付け可能である必要もない。

注釈

18.2 インデックスの種類

System.Index型は、開始インデックスまたは開始インデックスのいずれかを表す抽象インデックスを表します。

    public readonly struct Index : IEquatable<Index>
    {
        public int Value { get; }
        public bool IsFromEnd { get; }

        public Index(int value, bool fromEnd = false);

        public static implicit operator Index(int value);
        public int GetOffset(int length);
        public bool Equals(Index other);
    }

Index値は、intから構築され、負でないオフセットと、オフセットが終了 (bool) または開始 (true) のどちらであるかを示すfalseを指定します。 指定したオフセットが負の場合は、 ArgumentOutOfRangeException がスローされます。

Index first = new Index(0, false); // first element index
var last = new Index(1, true);     // last element index
var past = new Index(0, true);     // past-end index

Index invalid = new Index(-1);     // throws ArgumentOutOfRangeException

終了サンプル

開始インデックスを生成するintからIndexへの暗黙的な変換と、^から、from-end インデックスを生成するへの言語定義の単項演算子int (Index) があります。

暗黙的な変換と単項 ^ 演算子を使用して、上記の例を記述できます。

Index first = 0; // first element index
var last = ^1;   // last element index
var past = ^0;   // past-end index

終了サンプル

このメソッドGetOffset、抽象Index値から、指定したintのシーケンスの具体的なlengthインデックス値に変換されます。 Index値 (I) が from-end の場合、このメソッドはlength - I.Valueと同じ値を返します。それ以外の場合は、I.Valueと同じ値を返します。

このメソッドは、戻り値が有効なの範囲内にあることを確認0

手記: 結果の予期される使用は、 length 要素を持つシーケンスにインデックスを作成することであり、そのインデックス作成操作が適切なチェックを実行することが期待されるため、チェックは指定されません。 注釈

IndexIEquatable<Index>を実装し、抽象値に基づいて値が等しいかどうかを比較できます。それぞれのIndexプロパティとValueプロパティが等しい場合にのみ、2 つのIsFromEnd値が等しくなります。 ただし、 Index 値は順序付けされず、他の比較操作は提供されません。

注:Index 値は抽象インデックスであるため順序付けされません。一般に、シーケンス長を参照せずに開始インデックスの前または後に from-end インデックスが存在するかどうかを判断することはできません。 たとえば、 GetOffsetによってコンクリート インデックスに変換されると、それらの具象インデックスは同等になります。 注釈

Index値は、次のelement_access式 (§12.8.12) のargument_listで直接使用できます。

  • 配列アクセスとターゲットが 1 次元配列 (§12.8.12.2);
  • 文字列アクセス (§12.8.12.3)
  • インデクサー アクセスとターゲット型には、 Index 型 (§12.8.12.4) または Index 値が暗黙的に変換可能な型の対応するパラメーターを持つインデクサーがあります。
  • インデクサー アクセスとターゲット型は、暗黙的な Index サポートが指定されているシーケンス パターンに準拠しています (§18.4.2)。

18.3 範囲の種類

System.Range型は、IndexインデックスからStartインデックスまでのEndの抽象範囲を表します。

    public readonly struct Range : IEquatable<Index>
    {
        public Index Start { get; }
        public Index End { get; }

        public Range(Index start, Index end);

        public (int Offset, int Length) GetOffsetAndLength(int length);
        public bool Equals(Range other);
    }

Range 値は、2 つの Index 値から構成されます。

次の例では、intからIndexへの暗黙的な変換 (§18.2) と^ (§12.9.6) 演算子を使用して、各IndexRange値を作成します。

var firstQuad = new Range(0, 4);  // the indices from `0` to `3`
                                  // int values impicitly convert to `Index`
var nextQuad = new Range(4, 8);   // the indices from `4` to `7`
var wholeSeq = new Range(0, ^0);  // the indices from `0` to `N-1` where `N` is the
                                  // length of the sequence wholeSeq is used with
var dropFirst = new Range(1, ^0); // the indices from `1` to `N-1`
var dropLast = new Range(0, ^1);  // the indices from `0` to `N-2`
var maybeLast = new Range(^1, 6); // the indices from `N-1` to 5
var lastTwo = new Range(^2, ^0);  // the indices from `N-2` to `N-1`

終了サンプル

言語定義演算子.. (§12.10) は、Range値からIndex値を作成します。

..演算子を使用して、上記の例を記述できます。

var firstQuad = 0..4;  // the indices from `0` to `3`
var nextQuad = 4..8;   // the indices from `4` to `7`
var wholeSeq = 0..^0;  // the indices from `0` to `N-1`
var dropFirst = 1..^0; // the indices from `1` to `N-1`
var dropLast = 0..^1;  // the indices from `0` to `N-2`
var maybeLast = ^1..6; // the indices from `N-1` to 5
var lastTwo = ^2..^0;  // the indices from `N-2` to `N-1`

終了サンプル

..のオペランドは省略可能で、1 つ目の既定値は 0、2 番目のオペランドの既定値は ^0 です。

上記の例のうち 5 つを短縮するには、オペランドの既定値を使用します。

var firstQuad = ..4; // the indices from `0` to `3`
var wholeSeq = ..;   // the indices from `0` to `N-1`
var dropFirst = 1..; // the indices from `1` to `N-1`
var dropLast = ..^1; // the indices from `0` to `N-2`
var lastTwo = ^2..;  // the indices from `N-2` to `N-1`

終了サンプル

Range値は、次の場合に長さ L に対して有効です

  • およびRangeStartプロパティの End に関する具体的なインデックスは、0 ~ L の範囲です。
  • Startの具象インデックスが、次の具象インデックスより大きくないEnd

このメソッドは、引数を指定してGetOffsetAndLengthlength抽象Range値をタプルで表される具体的なRange値に変換します。 Rangeに関してlengthが有効でない場合、メソッドはArgumentOutOfRangeExceptionをスローします。

返される具象 Range タプルは、次の (S, N) 形式のペアです。

  • Sは範囲の開始オフセットであり、StartRange プロパティの具体的なインデックスです。
  • N は範囲内の項目の数であり、 End プロパティと Start プロパティの具象インデックスの差です。
  • lengthに関して計算される両方の値。

が 0 の場合、具象範囲の値はNです。 空の具象範囲には、具象の過去のインデックス (S) と等しい値が含まれる場合があります。空でない範囲は含まれません。 スライスに使用される Range (§18.1) のコレクションが有効で、そのコレクションに対して空の場合、結果のスライスは空のコレクションになります。

手記:上記の結果として、0 のRangeに関して有効で空のlength値を使用して、空のコレクションをスライスし、空のスライスが生成される可能性があります。 これは、コレクションが空の場合に例外をスローするインデックス作成とは異なります。 end note*

GetOffSetAndLength(6)で上記で定義した変数を使用します。

var (ix0, len0) = firstQuad.GetOffsetAndLength(6); // ix0 = 0, len0 = 4
var (ix1, len1) = nextQuad.GetOffsetAndLength(6);  // throws
   // ArgumentOutOfRangeException as range crosses sequence end
var (ix2, len2) = wholeSeq.GetOffsetAndLength(6);  // ix2 = 0, len2 = 6
var (ix3, len3) = dropFirst.GetOffsetAndLength(6); // ix3 = 1, len3 = 5
var (ix4, len4) = dropLast.GetOffsetAndLength(6);  // ix4 = 0, len4 = 5
var (ix5, len5) = maybeLast.GetOffsetAndLength(6); // ix5 = 5, len5 = 1
var (ix6, len6) = lastTwo.GetOffsetAndLength(6);   // ix6 = 4, len6 = 2

RangeIEquatable<Range>を実装し、抽象値に基づいて値が等しいかどうかを比較できます。それぞれのRangeプロパティとStartプロパティの抽象値が等しい場合にのみ、2 つのEnd値が等しくなります (§18.2)。 ただし、 Range 値は順序付けされず、他の比較操作は提供されません。

注:Range 値は抽象であり、一意の順序関係がないため、順序付けされません。 たとえば、 GetOffsetAndLengthによって具体的な開始と長さに変換されると、順序関係を定義できます。 注釈

Range値は、次のelement_access式 (§12.8.12) のargument_listで直接使用できます。

  • 配列アクセスとターゲットが 1 次元配列 (§12.8.12.2);
  • 文字列アクセス (§12.8.12.3);
  • インデクサー アクセスとターゲット型には、 Range 型 (§12.8.12.4) または Range 値が暗黙的に変換可能な型の対応するパラメーターを持つインデクサーがあります。
  • インデクサー アクセス (§12.8.12.4) とターゲットの型は、暗黙的な Range サポートが指定されているシーケンス パターン (§18.4.3) に準拠しています。

18.4 パターンベースのインデックスと範囲の暗黙的なサポート

18.4.1 全般

フォーム のelement_access式 (E[A]) がETを持ち、AIndexまたはRangeに暗黙的に変換できる単一の式である場合、次のように識別できません。

  • 配列アクセス (§12.8.12.2)
  • 文字列アクセス (§12.8.12.3)、または
  • 適切なアクセス可能なインデクサーが提供されないとしてのインデクサー アクセス (T)

その後、 T が特定のパターンに準拠している場合、式の暗黙的なサポートが提供されます。 Tがこのパターンに準拠していない場合は、コンパイル時エラーが発生します。

18.4.2 暗黙的インデックスのサポート

任意のコンテキストで、フォーム のelement_access式 (E[A]) の場合、Eは型Tを持ち、AIndexに暗黙的に変換できる単一の式です。有効でない場合 (§18.4.1)、同じコンテキスト内にある場合:

  • T は、 それをシーケンス として修飾するアクセス可能なメンバーを提供します (§18.1);そして
  • E[0] は有効であり、シーケンスとして T を修飾するのと同じインデクサーを使用します

その後、式 E[A] が暗黙的にサポートされます。

それ以外の場合、この標準の実装を制限することなく、式の評価順序は次のようになります。

  1. E が評価されます。
  2. A が評価されます。
  3. 実装で必要な場合は、 T のカウント可能なプロパティが評価されます。
  4. 同じコンテキストでintによって使用されるTE[0] ベースのインデクサーの get アクセサーまたは set アクセサーが呼び出されます。

18.4.3 暗黙的範囲のサポート

任意のコンテキストで、フォーム のelement_access式 (E[A]) の場合、Eは型Tを持ち、ARangeに暗黙的に変換できる単一の式です。有効でない場合 (§18.4.1)、同じコンテキスト内にある場合:

  • Tは、カウント可能とスライス可能の両方として修飾されるアクセス可能なメンバーを提供します (§18.1)

その後、式 E[A] が暗黙的にサポートされます。

それ以外の場合、この標準の実装を制限することなく、式の評価順序は次のようになります。

  1. E が評価されます。
  2. A が評価されます。
  3. 実装で必要な場合は、 T のカウント可能なプロパティが評価されます。
  4. SliceT メソッドが呼び出されます。