はじめに
プログラミングをしたりソースコードを見ていると、『何故先頭部や中盤に分けて変数を宣言しているのだろう?』と思われたことはないでしょうか?
この赤枠の部分ですが初めて見ると、どういった違いがあるんだろうってなりますよね。これは、プログラミング用語で上部の赤枠がグローバル変数で下部の赤枠はローカル変数と呼ばれています。
今回は、このグローバル変数とローカル変数についてご紹介します。
グローバル変数、ローカル変数とは?
そもそも、グローバル変数のグローバルという英語を和訳すと『国境を越えて地球全体にかかわるさま』という風になります。これをプログラミング用語っぽく置き換えると、『関数を超えてプログラム全体にかかわる』という風に置き換える事ができます。
では、反対にローカルという英語を和訳すと『特定の地域や場所に関連すること』という風になります。これをプログラミング用語に置き換えると『特定の関数にのみ関連する』という風に置き換える事ができます。
正にこの通りで、
この事を念頭において、先ほどのソースコードをもう一度見てみましょう。
上部の赤枠[G_prevtime]変数がグローバル変数で、下部の赤枠[L_prevtime]変数がローカル変数となる事がわかるでしょうか?
何故そうなるかというと、[G_prevtime]変数はどの関数にも属していない部分で宣言されています。反対に[L_prevtime]変数はtestLog関数内で宣言されていますよね。
ですので、[L_prevtime]変数はtestLog関数で完結し、仮に他の関数(OnTickなど)で[L_prevtime]変数を参照しようとしても参照できません。
グローバル変数と、ローカル変数にはこういった違いがあります。
あと、グローバル変数は殆どの割合で先頭部(関数外で宣言する必要があるので先頭)で宣言されます。なので、先頭部で宣言されている変数はグローバル変数なんだろうなと思いながらプログラムを読むとスムーズにプログラムを読めるようになりますよ。
グローバル変数の使用用途
まず、大前提としてローカル変数が基本形の変数です。基本はローカル変数を使うようにしましょう。グローバル変数はあくまでローカル変数では実現が難しい場合に使うようにします。
では、ローカル変数では実現が難しい場合(グローバル変数の使用用途)は大きく2つあります。
①プログラム全体で参照したい
グローバル変数はプログラム全体に関わる=プログラム全体どこからでも参照できるという事になります。ですので、A関数でグローバル変数に値を入れて、それをB関数でチェックし、それをC関数で出力という感じでどこからでも参照したり値の変更ができます。
ですので、複数の関数で使う値がある場合はグローバル変数にしたりします。
※ただし、値を引数で渡せばグローバル変数にする必要はないので作り手でこの辺はばらけます
②値を覚えておきたい
グローバル変数は、EAを終了させない限り値が無くなりません。(初期化されません)
ローカル変数の場合、例えばOnTick()内で変数を宣言していた場合、値動きの処理が終わったあと値は初期化されます。
ですので、値を覚えておきたい(前回のエントリー状況等の)場合はグローバル変数を使います。
グローバル変数の落とし穴
一見グローバル変数は、プログラム全体で使えたり記憶できる変数としてスペシャルな変数に見えるのですが、悪い部分が存在します。
①可読性が落ちる
グローバル変数を使うと、プログラムの読みやすさ『可読性』が低下します。短いプログラムなら可読性は低下しませんが、長いプログラムになればなるほど可読性が低下します。
このグローバル変数はどこで使われて、どこで値を入れているのか?が一目でわからなためです。
ローカル変数だと、関数内で完結するのでどこで使われてどこで値を入れているのかも全て関数内なので読みやすさは歴然です。
②影響箇所が増える
グローバル変数を使うと、プログラムを修正する際等の影響箇所が増えます。ここでグローバル変数に値入れてるけどちょっと変更したいなと思って、違う値を入れるとグローバル変数を使っている全ての処理に影響してきます。
思いもしないバグを引き起こす一番の原因になります。ですので、グローバル変数の値を変更したり、いらない部分を消したりとメンテナンスする際はプログラム全体を見直しながら修正しないといけません。
ローカル変数だと、入れる値を変更しようが変数を削除しようが影響するのは関数内だけなので影響箇所は限定されます。
③初期化忘れが起きる
グローバル変数を使うと、今そのグローバル変数に何が入っているのかを正確に理解しておく必要があります。グローバル変数は値を覚えておくといった特性がある反面、値を絶対に初期化しません。(私たちが自発的に行う必要があります)
ですので、値の初期化忘れでシステムにバグが生じるという事も日常茶飯事です。
実際に動かして確認してみよう
上記の内容を踏まえグローバル変数を使っていきましょう。適切に使えばとても便利な変数です。
では簡単なソースコードを実際に動かして確認してみましょう。
//+------------------------------------------------------------------+
//| practice_1.mq4 |
//| Copyright 2020, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
input int ptn_global = 0;
datetime G_prevtime=0;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit(){
//---
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick(){
//---
//テストログ関数を呼び出す
testLog();
}
bool testLog(){
datetime L_prevtime=0;
if(ptn_global==0){
if(Time[0] != L_prevtime){
L_prevtime = Time[0];
Print("新しいローソク足が描画されましたL:"+L_prevtime);
}
}else{
if(Time[0] != G_prevtime){
G_prevtime = Time[0];
Print("新しいローソク足が描画されましたG:"+G_prevtime);
}
}
return true;
}
//+------------------------------------------------------------------+
こちらは、チャートのローソク足が新しくできたら操作履歴にログを出力するというプログラムになります。
グローバル変数の『G_prevtime』とローカル変数の『L_prevtime』名以外は全く同じの処理をtestLog()関数内で行っています。
パラメータのptn_globalが0の時はローカル変数を使った場合の処理、1の時はグローバル変数を使った場合の処理を行うようにしています。
結果はどうなるでしょうか。
ローカル変数の場合
結果は、ローソク足が描画されたときにログが出力されておらず値動きのたびにログが出力されました。
理由は簡単で、
if(Time[0] != L_prevtime){
L_prevtime = Time[0];
Print("新しいローソク足が描画されましたL:"+L_prevtime);
}
Time[0]の値をL_prevtimeにセットしていますが、これは値動きが終わる度に、初期化されてしまうのでif文で判別している箇所は総じて[最新のローソク足の時間 != 0]となってしまうからです。なので値動きがある度にログが出力されてしまうんですね。
グローバル変数の場合
結果は、ローソク足が描画されたときにしっかりログが出力されていますね。
こちらは、
if(Time[0] != G_prevtime){
G_prevtime = Time[0];
Print("新しいローソク足が描画されましたG:"+G_prevtime);
}
Time[0]の値をG_prevtimeにセットしていますが、これは値動きが終わっても初期化されずしっかり時間を覚えているのでif文でしっかり判別できます。
trueとなる場合は[最新のローソク足の時間 != 1つ前のローソク足の時間]となります。
※前回のチェックから新しいローソク足が描画された場合
falseとなる場合は[最新のローソク足の時間 != 最新のローソク足の時間]となります。
※前回のチェックからローソク足がまだ描画されていない場合
グローバル変数とローカル変数の違いだけでこうも結果が変わってしまうんですね。
さいごに
以上が、『プログラミング初心者必見!グローバル変数、ローカル変数の違いと使い方について』です。
グローバル変数とローカル変数はプログラミングをするうえで重要になってきますので是非覚えておきましょう。
※プログラミング知識が無くてもEAが作れる!
※オンラインレッスン
コメント