※文章中に出てくる各用語については、なるべく関連記事のリンクを貼るようにしているので、講座記事を読み進めていく中で、「わからなくなってしまった」、「忘れてしまった」言葉が出てきたら、クリックして復習していただければと思います<m(__)m>
改めて前回の内容をおさらいをしておくと、
- input変数の宣言の後ろにダブルスラッシュ(//)を記述した場合、ダブルスラッシュ以降に記述した文言がinput変数名の代わりに、パラメーター設定画面に表示される。(一般的なコメントアウトとは違う作用となるので注意)
ということをお伝えしました。
今回は、関数について解説していきたいと思います<m(__)m>
関数については、すでに何度も登場していて↓
そのたびに関数とは
より簡単、かつ効率的にプログラムを動かす記述
であり、実生活で言えば
掃除機や電気炊飯器のような便利家電のようなもの
と考えてください、とお伝えしていました。
今回は 細かい説明をここまで保留にしてきた関数について、もう少し深堀りしたいと思います。
関数はMQL5に限らず、全てのプログラミング言語の中枢といっても過言ではない概念です。
今回の講座記事で勉強すれば、関数についての理解はバッチリです。是非楽しみながら読んで頂ければと思います。
関数とは?
関数を今までのような、砕けた例えではない形で説明するならば、
特定の仕事をこなす、コードの固まり
という言い方ができるでしょうか?
MQL5で言えば、MT5を使って自動売買プログラム(EA)を作るので、サーバー側にトレードの発注をしたり、損切り利確の価格を指定したり・・・といった作業をこなす関数などが必要になってきます。
これまでの講座記事でも何度も登場してきたComment関数やPrint関数もMQL5側で事前に用意している関数(組み込み関数)の1つです。
事前に用意されている関数(組み込み関数)に、自分が希望しているような作業をしてくれる関数がない場合は、関数を自分で作ることもできます。
関数をこれまで家電に例えてきましたが、市販の家電が気に入らなければ、DIY精神で、自分で作ってしまおう!という訳です。
基本的には組み込み関数を利用してEAを作っていくことが多いのですが、ある程度プログラミングに慣れてくると、それだけだと物足りなくなってくる局面が出てきます。
この「MQL5でEA作ろう講座」では、実際にEAを作る工程まで講座が進めば、その中でオリジナルの関数を作る工程も紹介していきたいと思います。
関数を作ってみる(関数の宣言)
機械を作るときに、機械の名前と大まかなコンセプトを発表するようなものです。
変数を作るときにも
データ型を選択して、
変数名を記述する。
という作業をしました。
これを変数の宣言というのですが、それの関数ヴァージョンですね。
関数の宣言には、
を記述しなくてはいけません。
・・・関数名はともかく、「戻り値」「引数」という謎の言葉がまた出てきました。
一つづつ見ていきましょう。
戻り値(return value)って何?
戻り値というのは端的に言えば、
関数が行った処理の結果
のことです。
「処理の結果」といきなり言われてもピンとこないかもしれません。
順を追って見ていきましょう。
まずは関数の宣言です。関数の宣言は以下のような記述で行います。
//double型の戻り値の、sampleFunctionという名前の関数を宣言する
double sampleFunction()
{
}
最初にデータ型をdouble型にして、関数名を sampleFunction としました。
これで、「double型の処理結果を返す関数をこれから作りますよー」
という記述ができました。
関数名 sampleFunctionの後ろの
( )
の中には
が入ります。引数というのは簡単に言えば
関数のパラメーター
です。引数については後述します。
( )の後ろの
{}
の中には、関数が行う処理内容を記述します。現時点では何も記述していないので、当然まだなにもできません。
※なお、戻り値がない関数の場合は、関数の宣言時、設定するデータ型の種類に
というキーワードを記述します。
voidというのは「型なし」という意味になります。
※詳しくは↓の記事リンクをご参照ください。
今まで見てきたOnTick関数やOnStart関数の頭にもvoidというキーワードがついていたことを思い出した方もいるんじゃないでしょうか?
例えば、同じ機械を比較しても、自動販売機はジュースなどの製品が出てくる、という役割を担っていますが、車の場合、役割は道を走ることであって、何か製品を出すわけではないですよね?
関数にも計算・処理した結果をデータとして提出する役割を担っている関数があり、その場合はデータ型を設定するのですが、
計算処理結果をデータ提出することとは別の役割をする関数もあって、その場合はvoidキーワードを用いる
という訳です。
何度も登場しているOnTick関数でいえば、「価格の変動があるごとに{}内に記述した処理を行う」という役割を担っている関数であり、何かの計算処理結果を算出することを目的とした関数ではないのでvoidキーワードが使われているわけです。
戻り値を返すための記述 「return」キーワード
double型の戻り値の、(=小数点付き数値を処理・計算する)
sampleFunction関数を作る、という宣言をしたのはいいのですが、関数にはその処理結果を「これが最終処理結果です」ということを知らせる記述をしなくてはいけません。
それが
というキーワードです。
関数が自販機だとするならば、
return キーワードを記述することは自販機に取り出し口を設置する作業を意味します。
ボタンを押して商品を選択しても、取り出し口がないと商品が取り出せませんよね。
//double型の戻り値の、sampleFunctionという名前の関数を宣言する
double sampleFunction()
{
//戻り値として0.5を返す
return 0.5;
}
↑のサンプルコードのように、{}内にreturnキーワード を記述した後にデータ型に適合した数値を入力します。
↑の例ではまだなにも計算や処理の記述を何もしていないため、いきなり「0.5」という数字を入れていますが、普通は計算結果を代入した変数をreturnキーワードの後に入力します。
※returnキーワードについては
という講座記事でも、解説しています。先に読んでも問題ないのでよろしければこちらも参照ください。
とりあえず、これで「0.5」という値を吐き出してくれる、sampleFunction関数が完成しました。
・・・でも完成しただけです。
自販機も完成したとしても、工場に置いたままじゃ誰も使えませんよね?
街中に設置してジュースを飲みたい人に買ってもらって初めて役に立ちます。
関数にとっての街中にあたるのが、OnTick関数やOnStart関数などのイベントハンドラーになります。
//double型の戻り値の、sampleFunctionという名前の関数を宣言する
double sampleFunction()
{
//戻り値として0.5を返す
return 0.5;
}
void OnStart()
{
//sampleFunction関数を呼び出す。
sampleFunction();
//ログ出力
Print(sampleFunction());
}
イベントハンドラーであるOnStart関数の中に、先ほど作ったsampleFunction関数を呼び出しました。
関数の呼び出し方は、
関数名を記述→()を記述(引数があれば引数を中に書く)→セミコロン(;)で締める。
という手順をたどります。
実行してみましょう。
予想通り、「0.5」が出力されました。
{}及び{}の中に書いた記述、今回で言えば
return 0.5;
は必要ありません。
returnの戻り値に直接「0.5」を入力するのではなく、変数で返してみましょう。
//double型の戻り値の、sampleFunctionという名前の関数を宣言する
double sampleFunction()
{
//double型の変数「varDouble」を宣言し、値を代入
double varDouble=0.5;
//変数「varDouble」の値を戻り値として返す
return varDouble;
}
void OnStart()
{
//sampleFunction関数を呼び出す。
sampleFunction();
//ログ出力
Print(sampleFunction());
}
変数「varDouble」に0.5を代入し、その変数「varDouble」をそのまま戻り値に記述しました。
この場合も最初のサンプルコードと同じくログ出力で0.5が出力されます。
また、
イベントハンドラーであるOnStart関数側でも、sampleFunction関数の処理結果を格納する変数を別途用意して、その変数をPrint関数の()内に記述してログ出力させることもできます。(というか、こちらの方が一般的です)
//double型の戻り値の、sampleFunctionという名前の関数を宣言する
double sampleFunction()
{
//double型の変数「varDouble」を宣言し、値を代入
double varDouble=0.5;
//変数「varDouble」の値を戻り値として返す
return varDouble;
}
void OnStart()
{
//sampleFunction関数を呼び出し、変数に代入
double receive=sampleFunction();
//ログ出力
Print(receive);
}
OnStart関数内にdouble型の変数「receive」を宣言し、sampleFunction関数の戻り値を格納しました。Print関数の()内に変数「receive」を記述してログ出力させても「0.5」という結果を得られます。
//stringe型の戻り値の、sampleFunctionという名前の関数を宣言する
string sampleFunction()
{
//string型の変数「varString」を宣言し、値を代入
string varString="こんにちわ";
//変数「varString」の値を戻り値として返す
return varString;
}
void OnStart()
{
//sampleFunction関数を呼び出し、変数に代入
string receive=sampleFunction();
//ログ出力
Print(receive);
}
データ型を文字列型(string型)にして、戻り値も文字列の「こんにちわ」にしてみました。
実行してみます。
予想通り「こんにちわ」が返ってきました。
このように、
関数の便利なところは、一度作ってしまえば細かい計算内容を記述しなおさなくてもいい、ということです。
関数を呼び出しさえすれば、同じ計算・処理を一瞬でしてくれます。
今回取り上げた例だと、まだまだ処理内容が簡単なものなので、関数のありがたみが伝わってこないですが、実際にEAを制作する段階(【中級実際にEAを作ろう編】以降)になると、実感していただけるのではないかな?と思います。
引数とは?
戻り値のところでも少し触れましたが、
引数は、要は
パラメーター
のことです。
機械・家電にもいろいろな種類がありますが、電源ボタンのONOFFでのみ動くものより、「~モード」「~モード」と細かい設定ができるものの方が、難しい仕事をできますよね?
引数もそれと同じです。
なので、簡単な関数で引数を設定する必要がなければ省略することもできます。
上記サンプルコードのsampleFunction関数も引数は設定されていませんよね?
では、今度は引数の設定の仕方を見ていきます。
引数(パラメーター)の設定方法
引数(パラメーター)の設定方法についてですが、
関数の宣言時に()内に、定められた文法に従って記述します。↓
/*intの戻り値の、sampleFunctionという名前の関数を宣言し、
整数型の引数を2つ設定する*/
int sampleFunction(int para1,int para2)
関数宣言時、関数名の後の()内にデータ型 変数名をコンマ(,)で区切って必要な数だけ記述する
という工程を踏みます。
上のサンプルコードのsampleFunction関数には整数型の変数「para1」「para2」を引数(パラメーター)として設定しました。
※ちなみに、サンプルコードに書かれている
/*intの戻り値の、sampleFunctionという名前の関数を宣言し、 整数型の引数を2つ設定する*/
の両端にある「/*」、「*/」は複数行に及ぶ文章をコメントアウトするための記述です。
コメントアウトとは該当部分をプログラムとして認識させないための記法です。
詳しくは↓をご覧ください。
引数(パラメーター)の設定が終わったので、今度は{}内に関数の処理内容を記述していきます。
/*intの戻り値の、sampleFunctionという名前の関数を宣言し、
整数型の引数を2つ設定する*/
int sampleFunction(int para1,int para2)
{
//int型の変数「varInt」を宣言
int varInt;
//para1+para2を足した結果をvarIntに代入
varInt=para1+para2;
//変数「varInt」の値を戻り値として返す
return varInt;
}
↑これで、
para1+para2を足した結果をvarIntに代入し、その結果を戻り値として返す関数の完成です。
「para1+para2って何だよ!足し算って数字を足すものだろ(; ・`д・´)」
と思った方、だから言ったじゃないですか、引数はパラメータだと。
関数を家電や機械だと考えるなら、今の段階というのは家電・機械を作っただけなんです。
電子レンジだって、温める時間を何分何秒と設定できる作りになっていますが、実際に何分何秒と設定するのは実際に使う時ですよね?
では実際に使ってみましょう。
どうやって使うのかは覚えていますでしょうか?
/*intの戻り値の、sampleFunctionという名前の関数を宣言し、
整数型の引数を2つ設定する*/
int sampleFunction(int para1,int para2)
{
//int型の変数「varInt」を宣言
int varInt;
//para1+para2を足した結果をvarIntに代入
varInt=para1+para2;
//変数「varInt」の値を戻り値として返す
return varInt;
}
void OnStart()
{
//sampleFunction関数を呼び出し、変数に代入
int receive=sampleFunction(2,7);
//ログ出力
Print(receive);
}
OnStart関数内で、sampleFunction関数を呼び出しました。
※関数宣言時の「para1」「para2」というのはあくまで変数名です。パラメータについている名前でしかないので、混同しないようにしましょう。
sampleFunction関数は第1引数と第2引数を足し合わせる機能になっているので、
2+7→9 という答えが返ってくるはずです。
MQL5 Program Fileを実行してみましょう
予想通りの結果が返ってきましたね。
これが関数の基本的な使い方になります。
補足 -仮引数と実引数-
ちなみに、この、関数宣言時に設定した[para1][para2]にあたる部分を仮引数といいます。
サンプルコードの例で言えば、OnStart関数内で実際に入力している値は(2,7)という整数値であり、[para1][para2]というのはあくまで「この関数を使う時には、整数値をこの[para1][para]というところに入れてくださいねー」というガイダンスでしかないです。
実際に入力している値は(2,7)の部分を実引数と言います。
第43回「値渡しと参照渡し」で改めて登場予定です。
まとめ
今回は関数 について解説しました。
今回の記事では以下のことを学びました
- 関数は特定の仕事をこなす、コードの固まりである。
今回は以上になります。
最後までお読みいただきありがとうございました<m(__)m>
コメント