LoginSignup
0
0

int,Index,Rangeをまとめたい

Last updated at Posted at 2024-05-19

配列の引数

配列の引数として、int型に加えて、Index,Range型が追加された。
これによって、関数の引数にもIndex,Rangeが使えるようになって、使い方の幅が広がった。
しかし、int,Index,Rangeそれぞれに対して関数のオーバーロードをすると面倒臭いケアレスミスの懸念が増える。

int,Index,Rangeを全て受けられるようにしたい

var ex = new Sum();
int i = ex[5];
int j = ex[^3];
int k = ex[2..5];

とできるクラスを作るときに

class Sum
{
    int[] values;
    public int this[int i] => values[i];
    public int this[Index i] => values[i];
    public int this[Range r] => values[r].Sum();
}

ではなく

class Sum
{
    int[] values;
    public int this[XRange r] => values[(Range)r].Sum();
}

とかけるようなXRangeクラスを作りたい。

もちろん、合計しない場合は、int,IndexとRangeで戻り値の型が違うので、あんまりメリットはない。
また、前述のように関数が1つの場合は、素直に全てオーバーロードを書いたほうが良いだろう。

それでも、同じような関数が複数あった場合に便利だと考えた。
というか必要に迫られて実装した。

新(例を見直した)
var ex = new Sum();
int i = ex[5, 3];
int j = ex[^3, ^2];
int k = ex[2..5, 3..8];

とできるクラスを作るときに

class Sum
{
    int[][] cells;
    public int this[Index row, Index column] => cells[row][column];
    public int this[Index row, Range columns] => values[row][columns].Sum();
    public int this[Range rows, Index column] => values[rows].Sum(r => r[column]);
    public int this[Range rows, Range columns] => values[rows].Sum(r => r[columns].Sum());
}

ではなく

class Sum
{
    int[][] cells;
    public int this[XRange rows, XRange columns] => cells[rows].Sum(r => r[columns].Sum());
}

とかけるようなXRangeクラスを作りたい。

もちろん、合計しない場合は、int,IndexとRangeで戻り値の型が違うので、あんまりメリットはない。
例は、行列の2次元だが、次元が増える分だけメリットも増えると思う。

XRangeクラス

前述で使用したXRange関数の実装はこれ

public class XRange
{
    public static implicit operator XRange(int i) => new(i..++i);
    public static implicit operator XRange(Index i) => new(i..Next(i));
    public static implicit operator XRange(Range r) => new(r);
    public static implicit operator Range(XRange r) => r.value;

    static Index Next(Index i) => new(i.Value + (i.IsFromEnd ? -1 : 1), i.IsFromEnd);

    readonly Range value;

    XRange(Range r) => value = r;

    public Index Start => value.Start;

    public Index End => value.End;

    public (int Offset, int Length) GetOffsetAndLength(int length)
    {
        var left = value.Start.GetOffset(length);
        var right = value.End.Value > length ? left + 1 : value.End.GetOffset(length);
        return (left, right - left);
    }
}

まとめ

暗黙の型変換を使って、int,Index,Rangeから変換できるようにした。
勝手に変換されてしまうので、ソースが読み難くなる気もする。
型変換を何回も挟むので、パフォーマンスも悪いと思われる。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0