Access2000VBA・Excel2000VBA独学~変数を宣言するとき(=作るとき)に、どんな形で作ったらいいか?の参考例(エラーを減らす・エラーが出たときに調べやすくする・可読性を上げる、などのために。)~
※まだ書きかけです。すみません。
※間違ってたらすみません。
※メモ書きなので、自分でも意味不明な箇所も多いです。ごめんなさい。
僕の最近思っている例です。
すみません。
代表的な事例としましては、「ハンガリアン記法」というものがあるようですが、僕の場合はそうじゃない方法を使っています。
(01)接頭語と接尾語
整数型、長整数型、バリアント型、など、どの型の変数かを、変数名の先頭に「接頭語(=プレフィックス)」として付けると、可読性も上がりますし、プログラムミスを発見しやすくなります。
ただ、その際に、どんな形で書くか、という問題があります。
僕の場合は、最近自分でも色々とプログラムを書いているうちに思ったのは・・・、原則としては「英語の小文字を1文字+_ (アンダーバー)」の、2文字で表現するが良いのではないか?と、思っています。
例えば、文字列型(String型)なら「 s_ 」と書き、整数型なら「 i_ 」、長整数型なら「 l_ 」、バリアント型なら「 v_ 」、オブジェクト型なら「 o_ 」と書く・・・、と、まあ、そんな感じです。
なお、1文字で足りなくなったら、2文字使うとか、大文字も混ぜる、とか、すればいいと思います。大文字を使うときは、「どうしても何らかのルールが必要なときだけ」にしたほうがいいかもしれませんが。
グローバルな変すならさらにその前に「 g_ 」(globalの頭文字)とか「 p_ 」(publicの頭文字)とかを付加すればよいと思います。
あと、何かに「接尾語」を使うときも、「 _ (アンダーバー)+何らかの英数文字」というかたちでアンダーバーを使えばいいと思います。また、接尾語の場合は、2文字とは決めていません。
順序が逆さになりますが、まず、アンダーバーを使う理由ですが、次のような効果がある気がします。
(a)VBAの組み込みの関数名、列挙名、定数名、などと明確に区別できる。
(※ 「組み込み」=予約語)
理由は、それらの語句にはアンダーバーが使われてないためです。
なのでコードを読み返すときに、「どれが変数か?」を探すときに「アンダーバーが付いているものは、ほとんどは ”自分が作った” 変数だ。」とわかります。
プログラムのミスをしたときは、「まずは変数名のつづりまちがい」から探すので、その際に変数がすぐに見つかると便利で都合がいいのですが、その目的が果たせます。
なお、イベントプロシージャの名前や自作関数の名前にアンダーバーを使うこともありますが、その場合は、必ず「Call」を使って(=書いて)呼び出す、というルールにすれなOKです。
そうすることで、「もし、”Call” の後に書かれた単語にアンダーバーが含まれていても、それは変数じゃないから無視していい。」ということにできす。なので、これも、明確に区別がつきます。
なお、そのような目的を果たすなら、アンダーバーの代わりに「★」などを使ってもよさそうですが、変数やプロシージャの名前に日本語を不用意に増やすとエラーやトラブルのモトとなることがあるので、できるだけ使わないようにしています。
Accessなどは、イベントプロシージャによく日本語の文字が含まれてしまいますが、そのような場合はしょうがないと思って、日本語の文字が含まれている文字を使っています。
ただ、標準モジュールに書くプロシージャの名前には、基本、日本語は使いません。
そのようにして、できるだけ、エラーを回避できるようにしています。
(b)名前のメイン部分にはアンダーバーをできるだけ使わないようにすれば、さらに区別がしやすくなる。「アンダーバーが付いたものは接頭語か接尾語しかない」という区別もできる。
例えば「何らかのデータを吸い込むシートの ”名前” 」というものを変数で書き表したい場合は「 s_ImportShtNm_01」とか「s_ImpShtNm_01」みたいな感じで変数を作成すればよいと思いますが、こういった場合に・・・、
「あ!、s_ は接頭語だな!」
「あ!、_01 は接尾語だな!」
「あ!、s_ImportShtNm_01 は組み込み語・予約語ではなくて、自分が作った変数だな!」
・・・と、すぐにわかります。
シートを「名前で」じゃなくて、「オブジェクトとして」扱えるような変数にしたい場合は・・・、
「 o_ImportSht_01」とか、(Object型、という意味での「o」)
「 v_ImportSht_01」とか、(Variant型、という意味での「v」)
「 ws_ImportSht_01」とか、(WorkSheetオヴジェクト型、という意味での「ws」)
・・・と、そんな感じで書けば、OKだと思います。
「 o_ImportSht_01 だからオブジェクト型か。インテリセンス機能が使えないけどいいか」(インテリセンス機能=ピリオドを打ったときにニョロっと出てくるドロップダウンリストメニューのこと)とか、
「 v_ImportSht_01 だからバリアント型か。インテリセンスが使えないけどいいか。内部でどんな型に自動変更されているかに注意しないとな。エラーになったらローカルウィンドウで調べないといかんかも?」とか、
「 ws_ImportSht_01」 だからWorkSheetオブジェクト型か。インテリセンス使えるな。」とか、
そういう判断がしやすいです。
これは「いちいち、プログラムの先頭の変数宣言の箇所をスクロールしてかえりみなくても、その場で、その行で、そういう判断ができる」、ということです。
そういう便利さがあります。
そのままの場所(行)で、ローカルウィンドウを見ながら、変数が何型になっているかや、どんな値が入っているかをチェックすれば、エラーが出たときに調べ物もしやすいです。
ブレークポイントを設定したり、Stopを書いたりして、「1行ずつのステップ実行」をするときにも、このことは便利です。
「1行ずつのステップ実行」をしているのに、「この変数ってこの行の時点では何型じゃないといけないんだったっけ?」といちいちスクロールで変数設定付近に戻るのは、とても面倒くさいですので。
s_ →String型 (一般変数:文字列型)
i_ →Integer型(一般変数:数値型の中の整数型)
l_ →Long型 (一般変数:数値型の中の長整数型)
db_ →Double型 (一般変数:数値型の中の倍精度浮動小数点型)
sg_ →Single型 (一般変数:数値型の中の単精度浮動小数点型:※ただし、小数計算では計算ミスが多いので、ビジネス用途ではあまり使わないほうがいい型)
d_ →Date型 (一般変数:日付型)
bl_ →Boolean型(一般変数:True/Falseの論理?型)
v_ →Variant型(一般変数としても、配列としても、単一オブジェクトとしてもコレクションとしても、オブジェクト配列としても、の変数)
o_ →Object型 (単一オブジェクトとしてもコレクションとしても、の変数
=実行時バインディングでもあるなとわかる。)
wb_ →Workbook型 (単一オブジェクトとしての変数=事前バインディングでもあるなとわかる。以下同じ。)
wbs_ →Workbooks型 (コレクションオブジェクトとしての変数)
app_ →Application型
rg_ →Range型 (コレクションオブジェクト的なもの)
ct_ →Chart型 (単一オブジェクト)
cts_ →Charts型 (コレクションオブジェクト)
cmb_ →CommandBar型 (単一オブジェクト)
cmbs_ →CommandBars型 (コレクションオブジェクト)
qt_ →QueryTable型(単一オブジェクト)
qts_ →QueryTables型(コレクションオブジェクト)
prm_ →Paramater型(単一オブジェクト)
prms_ →Paramaters型(コレクションオブジェクト)
(c)方向や機能、役割、を示す単語など、「何らかの意味を持つ言葉」も省略形でつける
吸い込むもの:Imp(importの略)
書き出すもの:Exp(exportの略)
ソースとなるもの:src、Src(sourceの略)
相手先(目的地、行き先)となるもの:dist、Dist(destinationの略)
ターゲット(対象?目標?的?)となるもの:Trg(targetの略)
読み込み:Read、Rd
書き込み:Write、Wrt
変数名や関数名などに、何らかの意味をもたせたいときも、単語を短く省略して書いています。一応、わかりやすくなるし、名前もできるだけ短い方が読みやすくなることはなるので・・・。
ただし、「Accessのクエリ」につける名前のように、「どういう処理をしたかが日本語で長く書かれていたほうがコードが読みやすくなる場合」は、オブジェクト(例えばクエリ)自体に日本語で長い名前を付けて、で、コード内でも、その長い名前を使って書いてしまう場合もあります。
変数名や関数名は基本、トラブルになるといけないので日本語は使いませんので、英語で短く書きますが、イベントプロシージャ名やクエリ名などは日本語で長く書いても今のところは大丈夫のようですので、でも一応用心しながら信用はせず、長い日本語名をつけています。
なお、例えばですが、o_WsImp01 とか、v_WsImp01 といった変数名を作った場合は、ああ、これは「オブジェクト型(=実行時バインディング)で・かつ・インポート・吸い込みするワークシートなんだな」、という感じで、「機能・役割」としてはそれだけでも十分にわかります。
ですので、名前を長く具体的に付ける必要もなく、短くできるので便利だと思います。
そのような感じで、「実際に具体的な名前をつける」よりも「機能・役割」だけの名前にしたほうが「かえってコードが読みやすくなる場合のある」ので、そのような場合は、短い省略形の単語を使います。
実際に何を代入したかの具体的な名前は、プログラムの冒頭に書く「Set = ・・・」のコードでわかりますので。
(d)基本、文字を2文字しか使わないので、他の文字が多少なりとも多く使える
(e)作り変え、作り足し、を想定して、連番をつける。
作り変え・作り足しをするときは、「似た用途の変数を増やす」ということも少なくないためです。連番をつけておくと『性格が同じでも異なる変数』ということがしやすい(見やすい)ので。「ひとつは01」、「もう一つは99」とか、「ひとつは01」、「もう一つは222」とか。あきらかに違う数字をつけてもいいですし。
あるいは、「数字で何かを表現する」、という自己ルールにしてもいいと思います。
数字をつけることで、メイン部分が同じ名前でも「違う変数」として使えることもプラスです。同じ名前の変数を使いすぎて、メモリ上で動きがおかしくなって、何らかの不具合が発生するといけませんので、その「事前回避」にもなります。
例えば変数名が同じものばかりを使うと、「エラーは出ないけどおかしな値が返ってくる」とかいったような、「デバッグが面倒くさい不具合が発生する」ことも稀にあるので、そういう無駄で面倒くさいことを避ける、ということです。(稀なため、逆に「変数名が原因と気づけないこともある」ので、それも面倒。)
特に関数の呼び出しをする場合、ひとつのプロシージャの中だけの話に収まりません。1つの処理の中で、すべての呼び出しモト・呼び出し先のプロシージャを含め、その変数・引数その他、すべて、基本的には全部違う変数名を使うほうが事故が少ないと思います。
パソコンは基本、「信用できない機械」、ですし、WindowsやExcelも基本、「信用できないソフト」、ですので・・・。エラーが出るはずのないところでエラーになることが実際にあります。
オブジェクト変数に代入するとエラーだけど、代入しないとエラーが消える、とか、そういったことが起こる機械・ソフトですので信用しないようにしないといけません。
(f)大文字の英語を最低限1文字、メイン部分の先頭には必ず入れる。(変数入力時に、つづりミスしたかしてないかが入力しているその場ですぐにわかるので。)
接頭語との区別もしやすいです。
VBEでは、変数名に大文字を用いると、宣言後のコード記述で、もし変数に小文字を使ったとしても(宣言通りに)大文字に自動変換されます。つまり、大文字で書いたところがちゃんと大文字になれば、「つづりを間違えなかった」ということになるのです。一応、そんなことの目安にも使えます。
ただ、僕の場合、変数名の記述は、基本、「コピペ」でやります。
ダブルクリックで変数名などを一発選択して、それをコピペします。
理由は事項のとおりです。
(g)変数を書くときは、ダブルクリックで選択して、コピペ、でもいい。
VBEでは、一つの単語は、「コメントアウトしていなければ、ほぼ、ダブルクリックで一発選択できる」ようになっています。
どんなに「長い変数名や、長いオブジェクト名、長い組み込みの単語(関数、列挙、定数など)」でも、ダブルクリックで「一発選択」できるようになっています。
ですので、変数名やオブジェクト名や組み込みの名前(関数名、列挙名、定数名、オブジェクト名など)は、手打ちするよりもダブルクリックで選択してコピペする方が入力間違いが格段に減ります。
例えば、Accessなどだと、クエリの名前を、「どのような機能を持っているかあえて日本語で長く書く、ということも僕はしているので、その際にドラッグで選択すると、「先頭や最後尾」の1文字分を選択し忘れたりしてしまいますが、ダブルクリックで選択すると選択ミスがありません。
また、コピペなので、綴りのミスもありません。
あと、もうひとつ、とっても重要なことですが、VBAでは、例えば『 関数に値を(引数として)渡すとき 』は、特に何も指定されていなければ(デフォルトで)「参照渡し」というもの になります。
しかし「参照渡し」の場合、『 呼び出し元のプロシージャから、呼び出した関数に リテラル値ではなくて "変数" を引数として渡してしまい、かつ、その ”引数” に関数側で何かを代入してしまうコードを書いていると 』、『 意図しない動作(ある意味バグ)を生む 』ことになってしまいます。(詳細は先生や先輩などに聞いてください。短くは僕には説明できないので・・・。以降の「※参考01」のコードを見てもらってもいいとは思いますが・・・。)
これは「初心者にはなかなか見抜けないバグを生む」ということになることがあるので、例えば僕のようなVBA初心者には絶対に教えないといけないことだと思うのですが、なぜかほとんどの初心者本や教室、Webサイトで「そのことを」、「真っ先には」、教えてくれません。
ほんとう、超いいかげんで・テキトーです。
なので「参照渡し」の場合(=つまり、ほとんどすべての関数呼び出しの場合)・とても注意が必要なのは、『 関数の中で、引数(変数)に何かを代入するようなコードを 』 (敢えて意図していないならば)安易に『 絶対に書かない 』、ということです。
※参考01
「参照渡し」のことを知らないために「ある意味バグ」のようなコードになってしまう例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
' ' Option Explicit '################################################################################################ '呼び出しモトのプロシージャ '################################################################################################ Sub test() Dim i As Integer Dim jjj As Integer i = 1 Call TestFunc(i) jjj = 1 Call TestFunc(jjj) Debug.Print (i) '「i」には関数の影響は何も無く、「1」が表示されると思いきや・・・「3」がイミディエイトウィンドウに表示されます。 Debug.Print (jjj) '「jjj」にも関数の影響は何も無く、「1」が表示されると思いきや・・・同じく「3」が・・・あとは同上です。 End Sub '################################################################################################ '関数側のプロシージャ(呼び出される側) '################################################################################################ Sub TestFunc(i As Integer) i = 3 End Sub ' ' |
一般的に、何らかの「引数を持つ自作関数」を書いた場合、
もし「変数」を引数として渡されていたとしても、
例えば上記の関数のように「i」を引数とした自作関数の場合、
「 ” i ” を何らかの変数に代入する」という処理が多いので、
=「変数 = i 」という処理をすることになることが多いため、
=「i」には何も代入しないため、
あまり問題にはならないです。
しかし、何らかの目的で上記の「TestFunc()」のコードのように
「 i = ×× 」というかたちで、
「引数に値を代入してしまう」という「逆のコード」を書くと、
(特に、引数に変数を指定してしまうと、)
その引数に指定した「呼び出しモトのプロシージャの変数」の値までもが、
その「××」の値に上書きされてしまいます。
これは、呼び出し元となるプロシージャの変数が、関数側の引数の変数と、「名前が同じでも・違っていても」、「関係ありません。」
理由は、「Sub test2(i As Integer)」と何も指定せずに書いた場合は、
「Sub test2(ByRef i As Integer)」と書いた、とみなされる「前提になっている」ためです。
つまり何も書かないと「 ”ByRef” が省略された」と「みなされてしまう」ということです。
「ByRef」とは、「変数に代入されている値のコピーをもらう・渡した」、
という意味ではなくて
「変数に通ずる "トンネル"・"どこでもドア" あるいは "ショートカット" をもらう・渡した」
という意味だからです。
それを防ぐには、関数側で「ByVal」を書きます。
上記の例だと、
「Sub test2(ByVal i As Integer)」みたいな感じで、変数設定の前に書きます。
そうすると関数に「変数」を引数として渡しても、
「変数に代入されている値のコピーを渡した」、と同じ意味になります。
「ByVal」とは、「変数に代入されている値の ”コピー” をもらう・渡した」、
という意味だからです。
「変数に通ずる "トンネル"・"どこでもドア" あるいは "ショートカット" をもらう・渡した」わけではないからです。
上記の例なら、「i」も「j」も、関数の影響は無く、「1」がイミディエイトウィンドウに表示されます。