Pointer
ポインターの変数や式は、別の変数 (配列、配列要素を含む) 、テーブル、またはフィールドへの参照です。 ポインタータイプのフィールドは、存在しません。
ポインターは、(プログラミングにおける) データを参照するための高度な方法を提供します。 4D ランゲージ使用時にテーブル・フィールド・変数・配列等にアクセスするには、単純に名前を用います。 ですが、名前を使用しないでデータを参照する、またはアクセスした方が便利な場合もあります。 ポインターを使うとこれが実現できます。
ポインターの背景にある概念は、日常生活でもよく使われています。 対象物を正確に知らないまま、それを示すことがあります。 たとえば、友人に対して "登録番号123ABDの車に乗ろう" と言わずに "君の車に乗ろう" と言う場合です。 つまり、"登録番号123ABDの車" を "君の車" で示したわけです。 この場合、"登録番号123ABDの車" はオブジェクトの名前で、"君の車" はオブジェクトを参照するためのポインターと考えることができます。
対象物を明示しないで参照できると、非常に便利です。 たとえば、友人が新しい車に買い替えても、同じく "君の車" と言うことができます。 ポインターも同じように機能します。 たとえば、同じポインターがある時は数値フィールド "Age" を参照し、別の時には数値変数 "Old Age" を参照することもできます。 いずれの場合にもポインターは数値データを参照しており、それは計算に使用することができます。
テーブル・フィールド・変数・配列・配列要素・オブジェクトを参照するためにポインターを使用することができます。 以下の表に、各タイプの例を示します:
型 | 参照時 | 使用時 | 代入時 |
---|---|---|---|
テーブル | vpTable:=->[Table] | DEFAULT TABLE(vpTable->) | n/a |
フィールド | vpField:=->[Table]Field | ALERT(vpField->) | vpField->:="John" |
変数 | vpVar:=->Variable | ALERT(vpVar->) | vpVar->:="John" |
配列 | vpArr:=->Array | SORT ARRAY(vpArr->;>) | COPY ARRAY (Arr;vpArr->) |
配列要素 | vpElem:=->Array{1} | ALERT (vpElem->) | vpElem->:="John" |
オブジェクト | vpObj:=->myObject | ALERT (vpObj->myProp) | vpObj->myProp:="John" |
ポインターの基本
ポインターの使用方法について例題を用いて説明します。 以下の例は、ポインターを通して変数にアクセスする方法を示します。 まず、変数を作成します:
$MyVar:="Hello"
$MyVar は、文字列 "Hello" を含む変数です。 $MyVar に対するポインターを作成します:
C_POINTER($MyPointer)
$MyPointer:=->$MyVar
ポインター記号 (->) は、"・・・に対するポインターを求める" ことを意味します。 この記号は、"ダッシュ" (-) の後に "大なり" (>) を付けて構成されます。 ここでは、$MyVar を参照するポインターを取得します。 このポインターは、代入演算子 (:=) で $MyPointer に対して割り当てられます。
$MyPointer は、$MyVar に対するポインターを格納する変数です。 $MyPointer は、"Hello" という $MyVar の値を含みませんが、その値を参照することはできます。 以下の式は $MyVar の値を返します:
$MyPointer->
前述の式は、"Hello" という文字列を返します。 ポインター記号 (->) をポインターの後につけると、参照先の値を取得することができます。 これをデリファレンス (参照外し) と呼びます。
ポインター記号 (->) を後につけたポインターは、その参照先を直接使うのと同義であることを理解することが重要です。 つまり、変数 $MyVar を使用することと、$MyPointer-> を使用することは、まったく同じ意味になります。 たとえば、以下のステートメントはアラートボックスに文字列 "Hello" を表示します:
ALERT($MyPointer->)
$MyPointer を使用して $MyVar の値を変更することもできます。 下記のステートメントは、変数 $MyVar に文字列 "Goodbye" を代入します:
$MyPointer->:="Goodbye"
この2つの $MyPointer-> を使用した例のとおり、$MyVar を使用するのとまったく同じ動作が実行されます。 以下の2つのステートメントも、同一の動作を実行します。両方とも、変数 $MyVar の現在の値をアラートボックスに表示します:
ALERT($MyPointer->)
ALERT($MyVar)
以下の2つのステートメントも、同一の動作を実行します。両方とも $MyVar に、文字列 "Goodbye" を代入します:
$MyPointer->:="Goodbye"
$MyVar:="Goodbye"
ポインター演算子
前提:
// vPtrA と vPtrB は同じ対象を参照します
vPtrA:=->anObject
vPtrB:=->anObject
// vPtrC は別の対象を参照します
vPtrC:=->anotherObject
演算 | シンタックス | 戻り値 | 式 | 値 |
---|---|---|---|---|
等しい | Pointer = Pointer | Boolean | vPtrA = vPtrB | true |
vPtrA = vPtrC | false | |||
異なる | Pointer # Pointer | Boolean | vPtrA # vPtrC | true |
vPtrA # vPtrB | false |
ポインターの使用例
テーブルへのポインター
テーブルの代わりにデリファレンスしたポインターを使用することができます。 以下のようなステートメントで、テーブルのポインターを作成します:
$TablePtr:=->[anyTable]
あるいは、以下のように Table
コマンドを使用してテーブルのポインターを得ることができます:
$TablePtr:=Table(20)
取得したポインターは、以下のようにデリファレンスしてコマンドに渡すことができます:
DEFAULT TABLE($TablePtr->)
フィールドへのポインター
フィールドの代わりにデリファレンスしたポインターを使用することができます。 以下のようなステートメントで、フィールドのポインターを作成します:
$FieldPtr:=->[aTable]ThisField
あるいは、以下のように Field
コマンドを使用してフィールドのポインターを得ることができます:
$FieldPtr:=Field(1;2)
取得したポインターは、以下のようにデリファレンスしてコマンドに渡すことができます:
OBJECT SET FONT($FieldPtr->;"Arial")
変数へのポインター
プロセス変数またはローカル変数のポインターを使う場合、参照される変数はポインターが使用される時点ですでに定義されていなければなりません。 ローカル変数は、それらを作成したメソッドの実行が終わると破棄され、プロセス変数もそれを作成したプロセスの終了時に削除される点に留意してください。 存在しない変数をポインターで呼び出そうとすると、インタープリターモードでは (「変数が設定されていません」という内容の) シンタックスエラーが起きます。コンパイルモードでは、さらに重大なエラーが発生する可能性があります。
ローカル変数のポインターを使用すると、プロセス変数の使用を控えることができます。 ローカル変数へのポインターは、同じプロセス内でのみ使用することができます。 デバッガーにおいて、別のメソッドで宣言されたローカル変数へのポインターを表示すると、ポインターの後ろの括弧内にそのメソッド名が表示されます。 例として、Method1 で以下のように書いたとします:
$MyVar:="Hello world"
Method2(->$MyVar)
Method2 実行中のデバッガーは $1 を次のように表示します:
$1 | ->$MyVar (Method1) |
---|---|
$1 の値は、次のようになります:
$MyVar (Method1) | "Hello world" |
---|---|
配列要素へのポインター
配列要素に対するポインターを作成することができます。 以下の例は配列を作成し、配列の最初の要素を指し示すポインターを変数 $ElemPtr に割り当てます:
ARRAY REAL($anArray;10) // 配列を作成
$ElemPtr:=->$anArray{1} // 配列要素へのポインターを作成
以下のように、ポインターの参照先である配列要素に値を代入することができます:
$ElemPtr->:=8
配列へのポインター
配列に対するポインターを作成することができます。 以下の例は配列を作成し、配列を指し示すポインターを変数 $ArrPtr に割り当てます:
ARRAY REAL($anArray;10) // 配列を作成
$ArrPtr:=->$anArray // 配列へのポインターを作成
ポインターの参照先はあくまでも配列であり、配列要素ではないことを理解することが重要です。 たとえば、デリファレンスしたポインターを以下のように使用できます:
SORT ARRAY($ArrPtr->;>) // 配列の並べ替え
配列の4番目の要素にアクセスするのに配列のポインターを使う場合は、以下のように記述します:
ArrPtr->{4}:=84
メソッドの引数としてのポインター
ポインターは引数としてメソッドに渡すことができます。 メソッド内で、ポインターの参照先の値を変更することができます。 たとえば、以下のメソッド takeTwo
は、2つのポインターを引数として受け取ります。 そして、最初の引数の参照先を大文字に変換し、2つめの引数の参照先を小文字に変換します。 当該プロジェクトメソッドのコードです:
//takeTwo プロジェクトメソッド
//$1 – 文字列フィールドまたは変数へのポインター。 これを大文字に変換します。
//$2 – 文字列フィールドまたは変数へのポインター。 これを小文字に変換します。
$1->:=Uppercase($1->)
$2->:=Lowercase($2->)
以下のステートメントではメソッド takeTwo
を使用し、フィールドの値を大文字に、変数の値を小文字に変換します:
takeTwo(->[myTable]myField;->$MyVar)
このフィールド [myTable]myField の値が "jones" であれば、"JONES" に変更されます。 他方、変数 $MyVar の値が "HELLO" であれば、"hello" に変更されます。
メソッド takeTwo で宣言されている引数の型と、引数として渡したポインターの参照先のデータタイプが一致していることが重要です。 この例では、ポインターの参照先は必ず文字列またはテキスト型でなければなりません。
ポインターへのポインター
より複雑な使い方として、ポインターを参照するポインターを使うことができます。 以下の例を考えます:
$MyVar:="Hello"
$PointerOne:=->$MyVar
$PointerTwo:=->$PointerOne
($PointerTwo->)->:="Goodbye"
ALERT(($PointerTwo->)->)
この例はアラートボックスに "Goodbye" を表示します。
各行について見ていきましょう:
- $MyVar:="Hello" --> この行は、変数 $MyVar に文字列 "Hello" を代入しています。
- $PointerOne:=->$MyVar --> 変数 $PointerOne に、変数 $MyVar へのポインターを代入しています。
- $PointerTwo:=->$PointerOne --> 新たな変数 $PointerTwo に、$MyVar を参照する $PointerOne へのポインターを代入しています。
- ($PointerTwo->)->:="Goodbye" --> $PointerTwo-> は $PointerOne を示し、$PointerOne は $MyVarを示しています。 つまり、($PointerTwo->)-> は、$MyVar を示しています。 結果として、文字列 "Goodbye" が $MyVar に代入されます。
- ALERT (($PointerTwo->)->) --> 先の説明と同様に $PointerTwo-> は $PointerOne を示し、$PointerOne は $MyVar を示しています。 つまり、($PointerTwo->)-> は、$MyVar を示しています。 結果として、アラートボックスには $MyVar の内容が表示されます。
以下の例では、$MyVar に "Hello" が代入されます:
($PointerTwo->)->:="Hello"
以下のステートメントは、$NewVar に $MyVar の値である "Hello" が代入されます:
$NewVar:=($PointerTwo->)->
重要: デリファレンスを複数おこなうには括弧が必要です。