配列

EGL 配列の規則は、配列の型によって異なります。

EGL では、以下の種類の配列がサポートされます。

すべての場合で、サポートされる次元の最大数は 7 です。

EGL では、配列の最初の要素にはインデックス 1 がありますが、多くの言語では最初の要素はインデックス 0 です。

配列リテラル

配列リテラルは、コンマで区切られたリテラルのリスト (その他の配列リテラルを含む) または式 (配列変数を含む) を大括弧で囲んだものです。 配列リテラルはそれぞれ型を持ち、配列に型が与えられているところで、例えば、配列変数のイニシャライザーとして使用されます。 下の表に、配列リテラルの例を示します。

表 1. 配列リテラル
配列リテラル
[ 1, 2, 3 ] SMALLINT[]
[ "hi", "Mom" ] STRING[]
[ new myRecord, new myRecord ] myRecord[]
[ (myPay < 0), (myPay > 0) ] BOOLEAN[]
[ [ 1, 2 ], [ 3, 4 ] ] SMALLINT[][]
[ 3, "cow", [ 4.5, 6.7 ] ] ANY[]

配列リテラル内の要素の型が異なる場合、推測される配列の型は ANY です。 配列内の各要素は、相互に互換性のある代入でなくてもかまいません

動的配列

変数の動的配列を、次のような (DataTable を除く) データ・パーツに基づいて宣言できます。
  • プリミティブ
  • DataItem
  • レコード (すべての型)
  • 委譲
配列そのものは、要素に依存しない ID を持ちます。
  • 配列名を使用 (arrayName.functionName() の構文を使用) し、 要素の数を実行時に増減して関数のセットを呼び出すことができます。『動的配列関数』を参照してください。
  • maxSize 配列固有プロパティーは、配列内で有効な要素の最大数を示します。デフォルト値は無制限で、要素の数はターゲット環境の要件によってのみ制限を受けます。 多次元配列においては、最初の次元のみが対象になります。
宣言の中で要素の数を指定する必要はありませんが、宣言した場合は、その数が初期の要素数を示します。 多次元の配列の場合には、以下のように各インデックスを個別の大括弧で囲みます。
multiDimensionArray INT[2][3];

動的配列を宣言するための構文を以下の例で示します。

  // 要素の数が 5 つ以下の配列
  myNames CHAR(30)[] { maxSize=5 };

  // 要素の数が 6 つ以下の配列で、
  // 初期の要素は 4 つ
  myDataItemArray myDataItem[4] { maxSize=6 };

  // 要素なしの配列
  // ただし、最大サイズは可能な限り最大となります。
  myRecordArray ExampleRecord[];

  // 3 つの要素の配列で、要素には
  // 値 1、3、5 が代入されます。
  position int[] = [1,3,5]; 

リテラル整数を使用して要素の数を初期設定できますが、変数と定数は、どちらも無効です。

その他の参照変数 (『参照変数』を参照) と同様に、配列変数は初期化してからでないと使用できません。
myIntArray INT[];
myIntArray[2] = 13; // causes NullValueException

myIntArray2 INT[3]
myIntArray2[2] = 13; // これは、規則に沿っています。
配列の配列を宣言する場合、初期の要素数が有効となるのは、指定された最も左側の次元と、それ以降、初期数が指定されない次元までの各次元です。 以下のような宣言が有効です。
  // 有効。maxsize で最初の次元の
  // 最大値を指定
  
  myIntArray01 INT[3][];
  myIntArray02 INT[4][2][] {maxsize = 12};
  myIntArray03 INT[7][3][1];

  // 次の例では、配列定数により、外側の配列が
  // 初期に 3 つの要素を持つことを示しています。
  
  // 外側の配列の第 1 要素は、2 つの
  // 要素 (値は 1 と 2) からなる配列です。
  
  // 外側の配列の第 2 要素は、3 つの要素
  // (値は 3、4、5) からなる配列です。
  
  // 外側の配列の第 3 要素は、2 つの
  // 要素 (値は 6 と 7) からなる配列です。
  
  myIntArray04 INT[][] = [[1,2],[3,4,5],[6,7]];
以下は、myInt04 配列が要素なしの配列として宣言されているにもかかわらず、 これら各要素に 3 つの要素が割り当てられている、無効な構文の例です。
  // 無効
  myInt04 INT[][3];
  myInt05 INT[5][][2];
ご使用のコードで、配列または配列要素を参照するときは、次の規則が適用されます。
  • インデックスは、整数に解決される任意の数式にすることが可能であり、関数の呼び出しも含めることができます。
  • コードで動的配列を参照するが、索引 (単数または複数) を指定しない場合は、配列全体が参照されます。

メモリー不足状態は致命的エラーとして扱われ、プログラムが終了します。

値の設定ブロックを使用して、次の例のように配列を初期化することができます。
myArray1 int[3] {1,2,3};  // 3 つの要素を持つ配列。値は 1、2、および 3。

これは、新しい配列を配列リテラル [1,2,3] と等価にするよりも効率的です。 配列リテラルの場合、EGL は myArray1 に値を割り当てる前に リテラル配列を作成します。 値の設定ブロックを使用することによって、myArray1 のみが作成されます。

ただし、配列の初期サイズがゼロであるため、次の宣言は失敗します。
myArray2 int[] {1,2,3}; // IndexOutOfBoundsException をスロー
なんらかの理由で、要素の初期数を指定せずに配列を作成する必要があるが、その配列を NULL にできない (後で要素を追加したい) 場合は、以下の構文を使用することができます。
myArray3 int[] {};  // ゼロ長、非ヌル配列

パラメーターおよび引数としての動的配列の使用

動的配列は、EGL 関数に引数として渡すことができます。関連するパラメーターは、引数と同じ型の動的配列として定義する必要があります。 また、各要素は、引数とパラメーターの両方で (存在する場合) 同じ長さおよび小数点以下の桁数にする必要があります。

プログラムや関数に渡される配列で、要素の数を指定することはできません。

以下は、動的配列をパラメーターとして使用する関数の例です。
  Function getAll (CustomerRecord myCustomers[])
   ;
  end

実行時に、パラメーターの最大サイズは、対応する引数に宣言された最大サイズになります。呼び出された関数は配列のサイズを変更することができ、その変更は呼び出し側コードで有効になります。

構造化フィールド配列

次の例に示すように、構造化レコード内のフィールドに複数の出現箇所を指定した場合に、 構造化フィールド配列を宣言します。
  Record ExampleStructuredRecord
    10 mySi CHAR(1)[3];
  end

myRecord という名前の付いた構造化レコード変数がその定義に基 づいている場合、名前 myRecord.mySi は、3 つの要素 (それぞれが 1 文字) からなる 1 次元配列を参照します。

構造化フィールド配列の使用法

以下のようなコンテキストでは、構造化フィールドの配列全体 (例えば、myRecord.mySi) を参照できます。
  • in 演算子によって使用される第 2 オペランドとして。この演算子は、指定された値が配列に含まれているかどうかをテストします。
  • sysLib.size() 関数のパラメーターとして。 その関数は、配列内の要素数を戻します。

それ自体が配列ではない配列要素は、他の要素と同様に 1 つ のフィールドであり、さまざまな方法で参照できます。 例えば、assignment 文の中で参照することも、関数呼び出し時の引数として参照することもできます。

要素の索引として、1 つの整数に解決される任意の数式を使用できますが、 その式に関数呼び出しを組み込むことはできません。

1 次元構造化フィールド配列

myRecord.mySi のような 1 次元配列の要素を参照するときは、配列の名前を指定し、その後ろに大括弧で囲んだ索引番号を指定します。 例えば、サンプルの配列の 2 番目の要素を myStruct.mySi[2] として参照することができます。 索引は、1 から配列の要素数までの間で変化します。 この範囲外で索引が指定されると、ランタイム・エラーが発生します。

単一の値を必要とするコンテキストにおいて、索引を指定せずに構造化フィールド配列の 名前を使用することはできません (可能性のある例外については、このトピックの『互換性』の項を参照してください)。

次の例に示すとおり、1 次元配列は副構造を持つことができます。
  Record Record01
    10 name[3];
      20 firstOne CHAR(20);
      20 midOne CHAR(20);
      20 lastOne CHAR(20);
  end

myRecord01 という名前の付いたレコードが前のレコード定義に基づいて いる場合、名前 myRecord01.name は、それぞれが 60 文字の長さを持つ 3 つ の要素の 1 次元配列を参照し、myRecord01 の長さは 180 になります。

副構造を参照しなくても、myRecord01.name 内の各要素を参照する ことは可能です。例えば、myRecord01.name[2] は 2 番目の要素を参照します。 また、要素内の副構造を参照することもできます。 例えば、固有性の規則が満たされている場合、以下のいずれかの方法で、2 番目の要素の最後の 20 文字を参照できます。

  myRecord01.name.lastOne[2]
  myRecord01.lastOne[2]	
  lastOne[2]

最後の例は、allowUnqualifiedItemReferences プロパティーが YES に設定されている場合のみ有効です。

別の種類の参照について詳しくは、『EGL の参照変数』を参照してください。

多次元構造化フィールド配列

複数の要素を持つ構造化フィールドに副構造があり、従属の構造化フィールドにも複数の要素がある場合、 その従属の構造化フィールドは、追加の次元を持つ配列を宣言します (『互換性』の項を参照)。

次のレコード・パーツについて検討します。
  Record Record02
    10 siTop[3];
      20 siNext CHAR(20)[2];
  end
myRecord02 という名前のレコード変数がそのパーツに基づいている場合、myRecord02.siTop の 1 次元配列の各要素は、それ自体が 1 次元配列になっています。例えば、3 つの従属 1 次元配列の 2 番目は myRecord02.siTop[2] として参照できます。 siNext 構造化フィールドは 2 次元配列を宣言します。 この配列の要素は、以下のいずれかの構文によって参照できます。
  // 行 1、列 2 とします。
  // 次の構文を強くお勧めします。
  // なぜなら、動的配列に対しても機能するからです。
  myRecord02.siTop[1].siNext[2]

  // 次の構文がサポートされます。
  // しかし、推奨されるものではありません。
  myRecord02.siTop.siNext[1,2]

参照されるメモリーの領域を明確にするため、多次元配列におけるデータの保存方法についてを考えてみます。 この例では、myRecord02 は 120 バイト構成です。 参照される領域は、それぞれが 40 バイトの長さを持つ、3 つの要素の 1 次元配列に分けられます。

  siTop[1]     siTop[2]     siTop[3]

さらに、この 1 次元配列の各要素は、同じメモリーの領域の中で、それぞれが 20 バイトの長さを持つ 2 つの要素の配列に分けることができます。

  siNext[1,1] siNext[1,2] siNext[2,1] siNext[2,2] siNext[3,1] siNext[3,2]
2 次元配列は、行が大きい順に保存されます。 これには、二重の while によるループで配列を初期化する場合、 1 行ごとに列を処理することでパフォーマンスを高めるという意味があります。 次の例はこれを示します。
  // i、j、myTopIndex、および myNextIndex は変数です。
  // myRecord02 はレコードです。
  // sysLib.size() は、構造化フィールドの要素数を戻します。
  i = 1;
  j = 1;
  myTopIndex = sysLib.size(myRecord02.siTop);
  myNextIndex = sysLib.size(myRecord02.siTop.siNext);
  while (i <= myTopIndex)
    while (j <= myNextIndex)
      myRecord02.siTop.siNext[i,j] = "abc";
      j = j + 1;
    end
    i = i + 1;
  end

多次元配列の各次元に応じた値を指定する必要があります。 例えば、myRecord02.siTop.siNext[1] という参照は、2 次元配列では無効です。

3 次元配列の宣言の例を以下に示します。
  Record Record03
    10 siTop[3];
      20 siNext[2];
        30 siLast CHAR(20)[5];
  end
配列添字を組み込む方法を理解するために、以下のように、添字が組み込まれない状況を考えてみます。
  • 変数名を先頭に置いて、段階的に従属する構造化フィールドの名前をピリオドで区切ってリストしていったものを指定します。例えば、
      myRecord03.siTop.siNext.siLast
  • 最下位レベル・フィールド名が変数内で一意である場合、次の例に示すように、変数名の直後にピリオドを付け、その後に最下位レベル・フィールドの名前を続けて指定できます。
      myRecord03.siLast
  • 最下位レベル・フィールドが所定の名前空間内で固有である場合は、次の例に示すように、そのフィールドのみを指定できます。
      siLast
次に、配列添字を配置するための規則について検討します。
  • 複数の要素のいずれかが有効な場合は、次の例のように、各レベルに 1 つの添字を指定できます。
      myRecord03.siTop[3].siNext[2].siLast[5]
  • 複数の要素の 1 つが有効なレベルである場合は、次の例のように、任意のレベルの一連の添字を指定できます。
      myRecord03.siTop.siNext[3,2].siLast[5]
  • 複数の要素の 1 つが有効なレベル、またはそれに従属するレベルである場合は、次の例のように、任意のレベルの一連の添字を指定できます。
      myRecord03.siTop.siNext.siLast[3,2,5]
  • 所定のレベルで、適切な数を超える添字を割り当てると、エラーが発生します。 次に例を示します。
      // 無効
      myRecord03.siTop[3,2,5].siNext.siLast
  • 添字を 1 つずつ大括弧に入れて分離することも、コンマで区切った一連の添字を使用することも、これら 2 つの使用法を組み合わせることもできます。 以下の例は有効です。
      myRecord03.siTop.siNext.siLast[3,2,5]
      myRecord03.siTop.siNext.siLast[3,2][5]
      myRecord03.siTop.siNext.siLast[3][2,5]
      myRecord03.siTop.siNext.siLast[3][2][5]

互換性

表 2. 配列の互換性に関する考慮事項
プラットフォーム 問題
COBOL 生成 動的配列に対して、多次元配列はサポートされません。
JavaScript 生成 サポートされるデータ型は、ANY、BIGINT、BIN (ただし、小数点以下の桁を含まない場合に限る)、Boolean、DataItem、DATE、DECIMAL、Delegate、Dictionary、FLOAT、INT、NUM、NUMBER、SMALLFLOAT、SMALLINT、STRING (ただし、サイズ制限を含まない場合に限る)、TIME、TIMESTAMP、NUM、MONEY、サービス・パーツ、インターフェース・パーツ、外部型 (ステレオタイプ JavaScript)、サポートされるデータ型による配列、 および非構造化の基本、例外、および SQL レコード・パーツです。

サポートされないデータ型は、ArrayDictionary、BIN (小数点以下の桁数を含むもの)、BLOB、CHAR、CLOB、DBCHAR、HEX、INTERVAL、MBCHAR、NUMC、STRING (サイズ制限を含むもの)、PACF、UNICODE、および構造化されたレコード・パーツです。

VisualAge® Generator 互換モード 単一の値を必要とするコンテキストにおいて、索引を指定せずに構造化フィールド配列の名前を使用すると、EGL では配列の最初の要素が参照されていると見なされます。

フィードバック