その他の型

この章では、Curl® 言語の非プリミティブ データ型を説明し、関連する情報を紹介します。具体的には、以下の項目について説明します。

クラス型

要約:
  • 文字列、配列、セット、およびハッシュ テーブル用の組み込みのクラスがあります。
  • すべてのクラスは非 null データ型です。
  • クラス名に # のプレフィックスを付ければ、拡張 "null を許容" データ型を作成できます。
クラスは、データ型として使用するために作成されます。Curl 言語に組み込まれているクラス、または define-class で作成するクラスは、有効なデータ型です。組み込みのクラスには、以下のものがあります。
null 値は、オブジェクトのプレースホルダです。コードで、同じクラスのオブジェクトであるかのように式のメソッド、フィールド、または他のプロパティにアクセスしようとしても、その式の値が null になる場合は、エラーになります。Curl 言語では、他のオブジェクト指向言語よりも優れた型安全性を提供するために、null 値の使用を制限しています。
Curl 言語では、クラス名は非 null データ型を表します。つまり、わかりやすいクラス名を使用して型が宣言される変数には、null 値を設定できないということです。このため、できるだけ非 null 型を使用することをお勧めします。
ただし、特定のクラスのオブジェクトと null 値の両方を含むデータ型を使用する必要がある場合は、次の特別な構文を使用して、指定されたクラス名から拡張データ型を作成できます。
構文:#<class-name>
説明:
class-name は、null を含めるためにデータ型を拡張するクラスの名前です。
そのような "null を許容" 拡張データ型は、変数のデータ型、プロシージャの戻り値のデータ型などとして使用できます。次の例では、クラス型 String と拡張データ型 #String を使用して 2 つの変数を作成しますが、一方の変数にのみ null 値を設定できます。
|| string-1 has the non-null String type.
|| It must be initialized when it is declared.
let string-1:String = "hello"

|| string-2 has the "maybe-null" #String type.
|| Here its initial value is null.
let string-2:#String
set string-2 = "good-bye"
Curl 言語のクラスの詳細については、「クラス」の章を参照してください。null の詳細については、「null」を参照してください。

文字列

要約:
  • 文字列とは、連続した文字のことです。
  • 変更できない文字列には String を使用します。
  • 変更できる文字列には StringBuf を使用します。
連続した文字を格納するには、文字列変数を使用します。Curl 言語には、文字列オブジェクト作成用の組み込みのクラスが数多くあります。次の表に、こうした文字列クラスを示します。
データ型説明各要素のサイズ (ビット)
StringUnicode 文字の不変文字列のクラス8、16、または 32
StringBufUnicode 文字の可変文字列のクラス32
通常は、String または StringBuf を使用して連続した文字を格納します。変更できない文字列 (不変文字列) には String を使用し、変更できる文字列 (可変文字列) には StringBuf を使用します。
文字列の詳細については、「文字列」の章を参照してください。

コレクション

要約:
  • コレクションは、データ型 (または any データ型) を共有するオブジェクトのグループであり、コレクションの格納およびアクセスを体系的に行うことができます。
  • Curl 言語には、配列、ハッシュ テーブル、セットに対する組み込みのクラスが用意されています。
  • 配列クラスを作成するには、Array-ofArray-2-of を使用します。
  • 制限されたサイズの配列をさらに効率的に作成するには、FastArray-of を使用します (高度な機能)。
  • ハッシュ テーブルを作成するには、HashTable-of を使用します。
  • セットを作成するには、Set-of を使用します。
コレクションは、同じデータ型のオブジェクトのグループです。数多くの異なる種類のコレクションがあり、コレクション内の要素の編成方法やアクセス方法はそれぞれ異なっています。Curl 言語には、以下の型のコレクションが用意されています。
Curl 言語には、コレクション作成用の組み込みのクラスと略記法が数多くあります。次の表に、このようなクラスとショートカットの一部を示します。
コレクション説明
Array-ofオブジェクトの 1 次元配列のクラス
Array-2-ofオブジェクトの 2 次元配列のクラス
FastArray-of機能制限付きオブジェクトの 1 次元配列のクラス
HashTable-ofオブジェクトのハッシュ テーブルのクラス
Set-ofオブジェクトのセットのクラス
Curl 言語には、共通する種類のコレクションを作成するときに役立つ数多くの略記法も用意されています。こうしたショートカットを利用すれば、以下の種類のコレクションを作成するときの省略化をすることができます。
ショートカット完全なクラス名
Array{Array-of any}
FastArray{FastArray-of any}
Set{Set-of any}
HashTable{HashTable-of any, any}
StringArray{Array-of String}
ByteVec{FastArray-of byte}
CharVec{FastArray-of char}
IntVec{FastArray-of int}
ObjectVec{FastArray-of Object}
StringVec{FastArray-of String}
コレクションの詳細については、「コレクション」の章を参照してください。

null

要約:
  • null は、拡張クラス型またはプロシージャ型の変数の値であり、オブジェクトをポイントすることは出来ません。
  • null をプリミティブ型の変数 (数量など)、または通常の非 null クラス型の変数に代入することはできません。
拡張クラス型またはプロシージャ型の変数に null 値が設定されている場合は、変数が現在オブジェクトを示していないことを表しています。変数にオブジェクトを代入すると、この変数は null 値ではなくなります。null が許されているデータ型の変数に、この値を明示的に代入することもできます。ただし、型の安全性の理由から、any 型の変数または #<class-name> 形式の拡張データ型の変数に限り、null 値を設定できます。
次のコード内の代入ステートメントは、null 値を設定できない変数 my-stringnull を代入しようとしているため、不正であることに注意してください。
{do
    let my-string:String = "hello"
    set my-string = null
}

--> 構文エラー!
同様に、次のコードにも不正な宣言が含まれています。つまり、宣言を最初に定義するときに、変数 my-string の初期値を指定していません。その結果、null という初期値を指定したことになっています。
{do
    let my-string:String
    set my-string = ""
}

--> 構文エラー!
上記の例は、次のように修正できます。
{do
    let my-string:String = ""
}
null 値を設定できる変数を宣言するには、次のようにデータ型の前に # 演算子を指定します。
{let my-string:#String}
拡張クラス型またはプロシージャ型の変数に非 null 値が設定されているかどうかを判別する場合は、その変数を null と比較します。次に例を示します。

例: 変数と null との比較
|| Declare a variable called x that is either of type VBox
|| or null, with no initial value.
{let x:#VBox}

|| Determine whether x is equal to null.
x is equal to null is ... {value x == null}

|| Set the value of x to an instance of the VBox class.
{set x = {VBox}}

|| Determine whether x is equal to null.
x is equal to null is ... {value x == null}
拡張クラス型またはプロシージャ型の変数の値をクリアするには、変数に null 値を代入します。次に例を示します。

例: 変数への null の代入
|| Declare a variable called x that is either of type VBox
|| or null, with no initial value.
 {let x:#VBox}

|| Set the value of x to an instance of the VBox class.
{set x = {VBox}}

|| Determine whether x is equal to null.
x is equal to null is ... {value x == null}

|| Set the value of x to null.
{set x = null}

|| Determine whether x is now equal to null.
x is equal to null is ... {value x == null}
non-null 式は、渡された非 null 値と、null を有効な値として除外するために変更されたデータ型を返し、引数が null と等しい場合は、エラーをスローします。この式は、非 null 型の変数に値を正当に代入できるように、値が null でないことを確認して、その値を非 null 型にキャストするために使用されます。
たとえば、{non-null x} 式は、x#String 型として宣言されている場合、String 型の値を返すか、xnull であればエラーをスローします。
つまり、null を使用すれば、以下のことができます。
if-non-null コンストラクト
組み込みの条件式コンストラクト if-non-null を使用すると、式に非 null 値が設定されている場合にのみ実行するコード ブロックを指定できます。次の 2 つの形式があります。
形式 1: {if-non-null [var-name[:type] = ] expr [, ...] then if-body}
形式 2: {if-non-null var-name then if-body }
形式 1 では、expr は評価される式です。この式の値が非 null の場合は、コード ブロック if-body が評価されます。var-name が存在する場合、それは、 if-body の評価用に expr の非 null 値が代入される変数の名前です。
形式 2 では、var-name は、テストされる式として機能し、それが非 null の場合は、コード ブロック if-body が評価されるときに同じ名前で使用できる、非 null 型にキャストされるローカル変数としても機能します。
APIバージョン6から、複数のカンマで区切られた条件を記述できるようになりました。このケースでは、それぞれの連続した式は、前の式が nullでない時だけ評価されます。if-body は、全ての条件が nullでない時にのみ評価されます。そうでない場合は。制御は、elseif句またはelse句に移ります。

プロシージャ

要約:
  • プロシージャは、タスクを実行するソース コードのブロックです。
  • プロシージャは、関連付けられたデータ型を持つ、Curl 言語のファーストクラス オブジェクトです。
Curl 言語プロシージャは、引数の指定や戻り値のデータ型を含む署名、およびプロシージャが呼び出されるたびに評価される Curl 言語式を含むソース コードのブロックで構成されます。
Curl 言語には、グローバル プロシージャ、匿名プロシージャ、および言語のファーストクラス オブジェクトとして機能するクラス プロシージャの 3 種類の主要なプロシージャがあります。
こうした各種プロシージャには、proc type (プロシージャ型) というデータ型が関連付けられています。このプロシージャ型で、引数のデータ型とプロシージャの戻り値のデータ型を定義します。プロシージャ型は、変数、フィールド、他のプロシージャに対する引数を宣言するときに他のデータ型と同様に使用できる有効なデータ型です。こうしたプロシージャのいずれかを適切なプロシージャ型の変数に代入し、それを引数として渡すか、別のプロシージャの戻り値のデータ型として返すことができます。
注意: 初期化されていないプロシージャ型の変数の値は、null になります。
グローバル プロシージャと匿名プロシージャの詳細については、「プロシージャと引数」の章を参照してください。クラス プロシージャについては、「クラス定数、クラス変数、およびクラス プロシージャ」のセクションを参照してください。

列挙型

要約:
  • 列挙型は、指定した要素の固定リストから成るデータ型です。
列挙型は、指定した要素の固定リストだけから成るデータ型です。たとえば、さまざまな種類のクマ (北極グマ、灰色グマ、パンダなど) を指定する列挙型を作成できます。
列挙型の各要素は、以下の属性を備えています。

列挙型の定義

列挙型を定義するには、define-enum 式を使用します。この式の構文は、次のとおりです。
構文:{define-enum [access] enum-name
element-list
}
説明:
accessオプションのアクセス属性です。有効な値は、packagelibrarypublic です。access を指定しない場合、アクセス属性は package を既定値とします。コードへのアクセスを同一パッケージ内に制限するには、package を指定します。すべてのソース コードから列挙型にアクセスできるようにするには、public を指定します。
enum-name列挙データ型の名前です。有効な Curl 言語識別子を指定します。
element-list
列挙型の要素を指定します。要素を区切るにはコンマを使用します。各要素は、次のような形式になります
element-name [= value]
ここで、element-name は要素の名前で、value は要素の値です。element-name は識別子です。value は、数値、charbool、または String として評価できるオプションの式です。値が指定されていない要素には、その値として整数が代入されます。値のない最初の要素には、値 0 が取得され、その値は、値が指定されていない後続の各要素に対して 1 ずつ増分されます。
たとえば、次のコードは、Bear という列挙型を作成します。
{define-enum Bear
    polar = "endangered",
    grizzly = "threatened",
    panda,
    pooh = "abundant"
}
この列挙データ型 Bear には、次の 4 つの要素があります。
列挙型の要素数を確認するには、enum-size を呼び出して、列挙型を引数として入力します。次の例は、Bear 内の要素数を示します。

例: 列挙型の要素数の判別
|| Declare an enumerated data type called Bear with four
|| elements: polar, grizzly, panda, and pooh.
{define-enum Bear
    polar = "endangered",
    grizzly = "threatened",
    panda,
    pooh = "abundant"
}

|| Determine the number of elements in the enumerated type.
{enum-size Bear}

列挙型プロパティの使用

次のいずれかの方法で、要素を参照できます。
構文
enum-name.element-nameBear.polar
{enum-name name = element-name}{Bear name = "polar"}
{enum-name index = index}{Bear index = 0}
{enum-name value = value}{Bear value = "endangered"}
要素の名前、インデックス、および値を取得するには、それぞれ以下の構文を使用します。
注意: 2 つ以上の要素の値が同じ場合は、リスト内の最初の要素が返されます。
次の例は、要素を参照してその名前、インデックス、要素値を取得するさまざまな方法を示します。

例: 列挙要素へのアクセス
|| Declare an enumerated data type called Bear with four
|| elements: polar, grizzly, panda, and pooh.
{define-enum Bear
    polar = "endangered",
    grizzly = "threatened",
    panda,
    pooh = "abundant"
}

|| Use the different ways to refer to an element in an
|| enumerated type to display the information for the
|| polar element of Bear.
{value Bear.polar.name}
{value Bear.polar.index}
{value Bear.polar.value}

{value {Bear name="polar"}.name}
{value {Bear name="polar"}.index}
{value {Bear name="polar"}.value}

{value {Bear index=0}.name}
{value {Bear index=0}.index}
{value {Bear index=0}.value}

{value {Bear value="endangered"}.name}
{value {Bear value="endangered"}.index}
{value {Bear value="endangered"}.value}

列挙型の変数

データ型が列挙型に設定される変数を宣言するには、次の構文を使用します。
let my-var:enum-name [= initial-value]
列挙型の変数に値を代入するには、2 通りの方法があります。明白な方法は、変数と同じ列挙型の要素として評価する式を代入することです。特に、列挙型の要素の完全な名前を使用できます。この名前は、上記のように要素名および修飾子としての列挙型名の組み合わせから成ります。
let my-bear:Bear = Bear.grizzly
最上位の式として {value my-bear} は、最初にその式に代入されたリテラル値と同じ形式で Bear.grizzly のように表示されます。各列挙型値には、その元のデータ型が組み込まれます。したがって、例に示すように、any 型の変数にそのような値を代入して、その変数の実行時の型をクエリすることができます。

例: 列挙型値の代入
{define-enum Bear
    polar, grizzly, panda, pooh
}
The value Bear.panda is of type {type-of Bear.panda}.
{let x:Bear = Bear.panda}
{br} x has value {value x}.
{let y:any = x}
{br} Now y has value {value y} and runtime type {type-of y}.
実際には、列挙型値は、ほとんどの場合、any 型ではなく対応する列挙型として定義された変数に代入されます。代入される値が 1 つの列挙型の 1 つの要素しか考えられないコンテキストの場合、Curl 言語では、選択された要素の名前から成る文字列の値を持つ式を代用できます。文字列は、次の例に示すように、列挙型の対応する要素に自動的にキャストされます。

例: 列挙型値への文字列の自動キャスト
{define-enum Bear
    polar, grizzly, panda, pooh
}
|| The value "panda" will be implicitly cast to Bear.panda
{let my-bear:Bear = "panda"}
{br} Initially my-bear has value {value my-bear}.

|| The value "pooh" can also cast implicitly to a Bear value:
{set my-bear = "pooh"}
{br} Now my-bear has value {value my-bear}.
上記の例で、my-bear に代入される文字列のいずれかを Bear 要素名でない文字列に置き換えて Execute を押すと、どのようなエラーになるかを確認してください。my-bear に数値を代入するとどのようになるかも確認してください。
注意: 多くの言語と異なり、Curl 言語は、列挙型値を整数として処理することや、列挙型の変数に整数を代入することはできません。ただし、数値を列挙型の要素として使用したい場合は、列挙型プロパティの使用セクションに示すように、各要素の順次 index またはユーザー設定可能な value プロパティを明示的に使用できます。
列挙型の変数の既定値は、その型の最初の要素です。このような理由から、次の例に示すように、列挙型の最初の要素として特別な既定の要素を使用することにしてもかまいません。

例: 列挙型の変数の使用
|| Declare an enumerated data type called Bear with four
|| elements: polar, grizzly, panda, and pooh.
{define-enum Bear
    UNKNOWN,
    polar,
    grizzly,
    panda,
    pooh
}
|| Declare but do not initialize a variable of type Bear.
{let my-bear:Bear}

|| Display the value assigned to the variable by default.
{value my-bear}

列挙型の値の繰り返し処理

次の例に示すように、for ループで列挙型の値を簡単に繰り返し処理できます。

例: 列挙型の繰り返し処理
{define-enum Bear
    polar = "endangered",
    grizzly = "threatened",
    panda,
    pooh = "abundant"
}

|| A vertical box for displaying the bear types.
{let bears:VBox =
    {VBox
        background = "tan"
    }
}

|| Add all the bears to the display box.
{for bear-type in Bear do
    {bears.add bear-type}
}

|| Show the box containing the list of bears.
{value bears}

any

要約:
  • 任意のデータ型の値を格納できます。
  • データ型:any
  • 既定値は null です。
any データ型は、関連付けられた変数が任意のデータ型の値を格納できることを示します。データ型が any である変数には、intfloatchar などのプリミティブ データ型を格納できます。この変数には、VBoxTextFlowBoxRectangleGraphic などの任意のオブジェクトを格納したり、null 値を設定することもできます。any 型として宣言された変数の既定値は null です。
データ型説明既定値
anyanynull
変数に格納される値のデータ型がわかっている場合は、any を使用しないでください。any データ型を使用しない理由は、以下を含めていくつかあります。
変数を宣言するときにデータ型を指定したくない変数に、any データ型を使用します。たとえば、命令シーケンスに応じて、さまざまな型のデータを保持する可能性のある変数には、any を使用します。
Curl 言語での変数の既定のデータ型は any です。データ型を宣言せずに変数を初期化する場合、any 型の変数として処理されます。そのような場合に、変数のデータ型を初期値から推測しないように心がけることが重要です。したがって、型指定されていない変数は、any 型を明示的に宣言された変数に対する上述の効率やエラー チェックに関しても同様に制限されます。