私がプログラミングを勉強しはじめた頃、関数の作り方を覚えてから一気にプログラミングが楽しくなりました。関数の作り方を覚えると、以下の様なメリットがあったからです。
関数を覚える前にごちゃごちゃと言いすぎてもよくわからないと思いますから、まずは関数がどの様な形式で表現されるのかを説明します。
戻り値の型 関数の名前(第1引数の型 第1引数名, 第2引数の型 第2引数名, ・・・) { // ここに処理を書きます。 return(戻り値); }
以前にも関数の形式をご説明しましたが、その時は引数については記述しませんでした。引数は必要なければなくてもいいのです。
では実際にコードを書いて行きましょう。
start関数を空にしたソースを準備しましたのでダウンロードしてお使いください。
・start関数が空の TestIndicator
以下はお渡ししたソースの内容です。
//+------------------------------------------------------------------+ //| TestIndicator.mq4 | //| Copyright 2013, Daigo | //| https://mtplace.biz/ | //+------------------------------------------------------------------+ #property copyright "Copyright 2013, Daigo" #property link "https://mtplace.biz/" #property indicator_chart_window //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int init() { //---- indicators //---- return(0); } //+------------------------------------------------------------------+ //| Custom indicator deinitialization function | //+------------------------------------------------------------------+ int deinit() { //---- //---- return(0); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int start() { return(0); } //+------------------------------------------------------------------+
今回もstart関数の修正から始めていきたいと思います。
まずは、文字列を10回出力するようにしてみます。以下は修正したstart関数です。(for文をご説明する際に使用したコードです)
int start() { string moziretu = ""; for(int i = 0; i < 10; i++) { moziretu = moziretu + "Hello MQL4\n"; } Comment(moziretu); return(0); }
これを元に関数を作っていきます。まずは「”Hello MQL4″を10行出力する関数」を作ることからはじめてみましょう。以下が修正後のソースです。
//+------------------------------------------------------------------+ //| TestIndicator.mq4 | //| Copyright 2013, Daigo | //| https://mtplace.biz/ | //+------------------------------------------------------------------+ #property copyright "Copyright 2013, Daigo" #property link "https://mtplace.biz/" #property indicator_chart_window //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int init() { //---- indicators //---- return(0); } //+------------------------------------------------------------------+ //| Custom indicator deinitialization function | //+------------------------------------------------------------------+ int deinit() { //---- //---- return(0); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int start() { OutputComment(); return(0); } //+------------------------------------------------------------------+ //| "Hello MQL4"を10行出力する関数 | //+------------------------------------------------------------------+ void OutputComment() { string moziretu = ""; for(int i = 0; i < 10; i++) { moziretu = moziretu + "Hello MQL4\n"; } Comment(moziretu); } //+------------------------------------------------------------------+
まず、start関数の内容が、34行目の”OutputComment();”のみとなりました。これは、OutputCommentという名前の関数の処理を実行するという意味です。
そして新たに40行目以降にOutputComment関数を自作しました。最初に”void”とありますが、この場所は「戻り値の型」を記述する場所でしたね。通常であればここには”int”や”string”といったデータ型が来るのですが、今回のように何も値を返さない関数の場合は”void” と記述します。とりあえず今この件については理解できなくて構いません。
この、OutputComment関数の内容は、先ほどのstart関数の内容がまるごと入っています。もちろん実行結果も全く同じです。これが関数作成の第1歩となります。
この例では「引数」が出てきていませんので、今度は引数について解説していきます。
作成したOutputComment関数は、呼び出しても「”Hello MQL4″を10行出力する」ことしか出来ません。
これに、「出力する行数」という引数を追加して、「”Hello MQL4″を任意の行数出力する関数」に改造してみたいと思います。
以下が、修正後のstart関数とOutputComment関数です。
int start() { OutputComment(10); return(0); } //+------------------------------------------------------------------+ //| "Hello MQL4"を任意の行数出力する関数 | //+------------------------------------------------------------------+ void OutputComment(int lineCount) { string moziretu = ""; for(int i = 0; i < lineCount; i++) { moziretu = moziretu + "Hello MQL4\n"; } Comment(moziretu); } //+------------------------------------------------------------------+
OutputComment関数に、lineCountという名前のint型の引数を追加しました。
OutputComment関数の中で、このlineCountという変数が使用されているのは43行目です。
以前はここが”10″となっていましたが、それを引数にしたのです。
そして、start関数からの呼び出し時に、引数に”10″を指定することによってlineCountに10が入り、結局「”Hello MQL4″が10行出力」されるのです。
この修正で、OutputComment関数は以前よりも便利な関数になりましたね。34行目のOutputComment関数の引数を”10″から任意の数字に変更するだけで、出力する行数を変更できるようになったわけですから。このように、ある機能を関数化すると、再度同じ処理をしたいと思った時に楽ができます。上の例では「出力する行数」だけ自分で決めれば良いわけですから。逆に、このように楽をしたい場合に、関数を作るのです。
もう一つ重要な理由としては、「処理をシンプルに表現できるようになる」という事があります。上の例では、メインの処理であるstart関数が、圧倒的にシンプルになっていると思います。全体的な流れはstart関数で作りますから、後でstart関数を見た時にシンプルで分かりやすいほうが良いことが多いのです。
※ただし、start関数のコードの行数が少なければ少ないほど良いと言うわけではありません。あまりにも関数が多すぎると、逆にソースが読みづらくなってしまうこともありますから。
さて、練習として「出力する文字も引数に」してみましょう。以下が修正後のソースです。
int start() { OutputComment(10, "Hello MQL4"); return(0); } //+------------------------------------------------------------------+ //| 任意の文字列を任意の行数出力する関数 | //+------------------------------------------------------------------+ void OutputComment(int lineCount, string mozi) { string moziretu = ""; for(int i = 0; i < lineCount; i++) { moziretu = moziretu + mozi + "\n"; } Comment(moziretu); } //+------------------------------------------------------------------+
OutputComment関数にstring型の引数”mozi”を追加しました。この引数は45行目で使用されます。
そして、34行目のOutputComment関数の呼び出し時に、第2引数に”Hello MQL4″を指定しています。
結果は全く同じです。しかし、OutputComment関数は更に便利になり、出力する行数だけでなく、出力する文字列も指定できるようになりました。
実はさらに便利な機能もあって、例えば今作ったOutputComment関数の第2引数は、ほとんどの場合”Hello MQL4″でいいんだけど、たまに変更したいこともある、というような場合は以下のようにします。
int start() { OutputComment(10); return(0); } //+------------------------------------------------------------------+ //| 任意の文字列を任意の行数出力する関数 | //+------------------------------------------------------------------+ void OutputComment(int lineCount, string mozi = "Hello MQL4") { string moziretu = ""; for(int i = 0; i < lineCount; i++) { moziretu = moziretu + mozi + "\n"; } Comment(moziretu); } //+------------------------------------------------------------------+
40行目の第2引数の後に「 = “Hello MQL4″」を追加しました。こうすると、関数呼び出しの時に第2引数が省略された場合に自動的に”Hello MQL4″が使用されるようになります。もちろん第2引数を指定した場合はそれが使用され、”Hello MQL4″は無視されますのでご安心を。
次に、戻り値がある場合の関数定義の例を説明していきます。
ではまず、2つの整数を引数に取り、その2つの整数の足し算の結果を返す関数を作ってみましょう。普通はそんな単純な処理を関数化することはないですが(笑)
int start() { int result = Add(10, 5); Comment(result); return(0); } //+------------------------------------------------------------------+ //| 2つの整数の足し算の結果を返す関数 | //+------------------------------------------------------------------+ int Add(int num1, int num2) { int sum = num1 + num2; return(sum); } //+------------------------------------------------------------------+
int型の値を返すAdd関数を作りました。第1引数、第2引数ともにint型で、足し算の結果もintで返すため、戻り値の型はvoidではなくintにします。この関数は、最終的に「return(戻り値);」で完了します。このように戻り値がvoidでない場合は「return(戻り値);」が必要になります。関数の宣言時にvoid以外を指定したということは「return(戻り値);」を使って戻り値の型の値を返しますと約束したことになるのです。残念ながら「return(戻り値);」を忘れてもコンパイルエラーは出ないようですが、必ず必要と思っておいて下さい。
今度は「2つの整数の足し算の結果を文字列で返す」関数を作ってみます。
int start() { string result = Add2(10, 5); Comment(result); return(0); } //+------------------------------------------------------------------+ //| 2つの整数の足し算の結果を文字列で返す関数 | //+------------------------------------------------------------------+ string Add2(int num1, int num2) { int sum = num1 + num2; return(num1 + "と" + num2 + "を足すと" + sum + "になります。"); } //+------------------------------------------------------------------+
今度は結果を文字列で返す関数ですから、41行目のように戻り値の型はstringになりますね。そして、足し算の結果を文字列で返しますから、44行目のreturn文の中で返す文字列の内容を作り出しています。結果「10と5を足すと15になります。」と出力されます。
これで簡単なものであれば関数を作ることが出来ると思います。関数が作れるということは、当然のことながら関数を使えるということになります。関数を使うことは、関数を作ることより簡単です。関数が使えるようになったということは、MT4で出来ることが一気に多くなったということです!インジケーターを作成するにはもう少し知っておかなければならない基本事項がありますので、もう暫くの間基本的な内容の解説になりますが、頑張ってください。