4D v16.3プロジェクトメソッド |
|||||||||||||||||||||||
|
4D v16.3
プロジェクトメソッド
|
引数の型 | どのように渡されるか | 補足 |
スカラー型(数値、テキスト、日付など)のフィールド、変数、あるいは式 | 値として | ポインターを通して参照として渡すことも可能、以下を参照のこと |
オブジェクト型のフィールド、変数あるいは式 | 参照として | 以下の例題参照 |
コレクション型の変数あるいは式 | 参照として | |
ポインター型の変数あるいは式 | 参照として | メソッドにポインタを渡すを参照のこと |
配列 | 引数として直接は渡せません | ポインターを通して参照として渡すことは可能、配列とポインタを参照のこと |
テーブル | 引数として直接は渡せません | ポインターを通して参照として渡すことは可能、ポインタを参照のこと |
メソッドの引数として、スカラー型のフィールド、変数、あるいは式を使用する場合、値のコピーのみが渡されます。
$1、$2... はローカル変数であるため、これらはサブルーチン内でのみ利用可能であり、サブルーチンの終わりにこれらは消去されます。このため、サブルーチンは、呼び出しメソッドレベルにおいては引数として渡された実際のフィールドや変数の値を変更することはできません。例えば:
` MY METHODからのコードの一部
` ...
DO SOMETHING([People]Last Name) ` [People]Last Name が"williams"であるとする
ALERT([People]Last Name)
` DO SOMETHINGメソッドのコード
$1:=Uppercase($1)
ALERT($1)
DO SOMETHING メソッドによって表示されたアラートボックスでは"WILLIAMS"と表示され、MY METHODメソッドによって表示されたアラートボックスでは"williams"と表示されます。メソッドは$1 引数の値をローカルな範囲で変更しましたが、これはメソッドによって渡された[People]Last Name フィールドの値には影響しません。
DO SOMETHING メソッドがフィールドの値を実際に変更するためには、2通りのやり方があります:
1. メソッドにフィールドを渡すのではなく、ポインターを渡す。この場合、以下のようにコードを書きます:
` MY METHODメソッドのコードの一部
` ...
DO SOMETHING(->[People]Last Name) ` [People]Last Name が"williams"であるとする
ALERT([People]Last Name)
` DO SOMETHINGメソッドのコード
$1->:=Uppercase($1->)
ALERT($1->)
ここでは引数はフィールドではなく、フィールドへのポインターです。そのため、DO SOMETHING メソッド内においては$1 引数はフィールドの値ではなく、フィールドへのポインターになっています。$1 引数によって参照されていたオブジェクト(上記コード内での$1-> )は実際のフィールドです。その結果、参照されたオブジェクトを変更すると、その影響はサブルーチンのスコープを超え、実際のフィールドも変更されます。この例題の中では、両方のアラートボックスに“WILLIAMS”と表示されます。
ポインターについてのより詳細な情報については、ポインタの章を参照してください。
2. DO SOMETHING メソッドに"何かさせる"より、メソッドを値を返すように書き直すこともできます。その場合、以下のようにコードを書くことができます:
` MY METHODのコードの一部
` ...
[People]Last Name:=DO SOMETHING([People]Last Name) ` [People]Last Name が"williams"であるとする
ALERT([People]Last Name)
` Here the code of the method DO SOMETHING
$0:=Uppercase($1)
ALERT($0)
このサブルーチンによって値を返す2番目の方法は、"関数を使用"という言い方をします。これは次の段落に詳細な説明があります。
メソッドの引数としてオブジェクト型あるいはコレクション型の変数、式、フィールドを使用する場合、実際のソースの値への参照が渡されます。この場合、$1、$2... には値ではなく参照が格納されます。$1、$2... 引数の値をサブルーチン内で変更した場合、これらの変更はソースとなるオブジェクトやコレクションが使用されているところへと伝播します。これはポインターに対する原理と同じものですが、ただし$1、$2... 引数はサブルーチン内で参照を解錠する必要がありません。
例: //CreatePerson メソッドはオブジェクトを作成し引数として送る
C_OBJECT($person)
$person:=New object("Name";"Smith";"Age";40)
ChangeAge($person)
ALERT(String(OB get($person;"Age")))
//ChangeAge メソッドは受け取ったオブジェクトのAge属性に10を加える
C_OBJECT($1)
OB SET($1;"Age";OB Get($1;"Age")+10)
ALERT(String(OB get($1;"Age")))
CreatePerson メソッドを実行した場合、どちらのメソッドに置いても同じ参照が扱われているため、両方のアラートボックスにおいて”50”と表示されます。
4D Server: 同じマシン上で実行されないメソッド間で引数が渡された場合(例えばサーバー上で実行オプションが使用された場合など、プロジェクトメソッドプロパティ参照)、参照は利用できません。この場合は、参照の代わりにオブジェクトとコレクション引数のコピーが送られます。
メソッドからデータを返すこともできます。値を返すサブルーチンを関数と呼びます。
値を返す4Dコマンドや4Dプラグインコマンドも関数と呼びます。
以下の行は、文字列のデータ長を返すLength関数を用いたステートメントです。このステートメントは、Length関数がMyLengthという変数に値を返します。
MyLength:=Length("How did I get here?")
どのようなサブルーチンでも値を返すことができます。返す値をローカル変数$0に格納します。
例えばUppercase4という以下の関数は、始めの4文字を大文字に変換した文字列を返します:
$0:=Uppercase(Substring($1;1;4))+Substring($1;5)
以下は、Uppercase4 関数を使用するメソッドの例です:
NewPhrase:=Uppercase4("This is good.")
変数NewPhrase には“THIS is good.”が格納されます。
戻り値 $0はサブルーチン内でローカル変数です。サブルーチンの中では$0を通常のローカル変数と同様に使用できます。例えば、前例のDO SOMETHINGにおいて、$0は最初に大文字に変換した$1の値を割り当てられ、その後ALERT コマンドの引数として使われました。サブルーチンの中では、他のローカル変数と同じ方法で$0を使うことができます。サブルーチンが終わる時の$0の値を呼び出し元のメソッドに戻すのは4Dの役割です。
プロジェクトメソッドは、自分自身を呼び出すことができます。例えば:
これは再帰呼び出しと呼ばれています。4D言語は再帰呼び出しを完全にサポートしています。
例題を見てみましょう。以下のフィールドから成る[Friends and Relatives] テーブルがあります:
- [Friends and Relatives]Name
- [Friends and Relatives]ChildrensName
こ の例題では、フィールドの値は重複しない、すなわち同じ名前の人間はいないとします。名前を指定することで、以下のような文を作成します:“A friend of mine, John who is the child of Paul who is the child of Jane who is the child of Robert who is the child of Eleanor, does this for a living!”:
1. この文を以下のように作成できます:
$vsName:=Request("Enter the name:";"John")
If(OK=1)
QUERY([Friends and Relatives];[Friends and Relatives]Name=$vsName)
If(Records in selection([Friends and Relatives])>0)
$vtTheWholeStory:="A friend of mine, "+$vsName
REPEAT
QUERY([Friends and Relatives];[Friends and Relatives]ChildrensName=$vsName)
$vlQueryResult:=Records in selection([Friends and Relatives])
If($vlQueryResult>0)
$vtTheWholeStory:=$vtTheWholeStory+" who is the child of "+[Friends and Relatives]Name
$vsName:=[Friends and Relatives]Name
End if
Until($vlQueryResult=0)
$vtTheWholeStory:=$vtTheWholeStory+", does this for a living!"
ALERT($vtTheWholeStory)
End if
End if
2. 以下の方法でも作成できます:
$vsName:=Request("Enter the name:";"John")
If(OK=1)
QUERY([Friends and Relatives];[Friends and Relatives]Name=$vsName)
If(Records in selection([Friends and Relatives])>0)
ALERT("A friend of mine, "+Genealogy of($vsName)+", does this for a living!")
End if
End if
再帰関数Genealogy ofは以下の通りです:
` Genealogy of プロジェクトメソッド
` Genealogy of ( String ) -> Text
` Genealogy of ( Name ) -> Part of sentence
$0:=$1
QUERY([Friends and Relatives];[Friends and Relatives]ChildrensName=$1)
If(Records in selection([Friends and Relatives])>0)
$0:=$0+" who is the child of "+Genealogy of([Friends and Relatives]Name)
End if
Genealogy ofメソッドが自分自身を呼び出していることに注目してください。
最初に挙げた方法は反復性のアルゴリズムです。2番目に挙げた方法は再帰呼び出しのアルゴリズムです。
前述の例題のようなコードを実装する場合、反復性や再帰呼び出しを使用してメソッドを書くことができるということに注目してください。一般的に、再帰呼び出しは、より明瞭で、読みやすく、維持しやすいコードを提供します。ただし、この使用は必須ではありません。
4D内での再帰呼び出しの代表的な使用方法は以下の通りです:
重要: 再帰呼び出しは、必ずある時点で終了する必要があります。例えばGenealogy ofメ ソッドが自身の呼び出しを止めるのは、クエリがレコードを返さないときです。この条件のテストをしないと、メソッドは際限なく自身を呼び出します。 (メソッド内で使用される引数やローカル変数と同様に) 再帰呼び出しを行う容量が一杯になると、最終的に4Dは“スタックがいっぱいです”エラーを返します 。
プロダクト: 4D
テーマ: プログラミング言語の構成要素
ランゲージリファレンス ( 4D v16)
ランゲージリファレンス ( 4D v16.1)
ランゲージリファレンス ( 4D v16.2)
ランゲージリファレンス ( 4D v16.3)