エクセル

【VBA入門】関数の作り方

エクセル

[PR]当サイトはアフィリエイト広告を利用しています。

はじめに

この記事は

●プログラマーの国家資格を持つ筆者が教えるVBAの独学ロードマップ

の中の一つのレッスンです。対象は「関数」です。

今回は以前このブログでTermuxの解説をしたときに作成したPythonコードをVBAの関数機能でやってみようというお話です。

●AndroidスマホでPythonプログラムが動く~Termuxが便利

塩ビ管の体積を求めるという問題に取り組みます。

まず関数とは何かということを解説したのち、例題を解いて使い方に慣れましょう。

関数を使うことでコードが見やすくなるだけではなく、バグも減らすことができます。

決まった処理は関数化して役割を分けましょう。

関数とは

関数というのは次のようなものです。

決まった処理を行って、何らかの値を出力するもの

こう書くとかなり抽象的なので、簡単な関数を書いてみます。

Function sample(a As Integer)
    sample = a + 1
End Function
Sub sample2()
    Dim b As Integer
    b = sample(2)
    MsgBox b
End Sub

ここでFunctionからEnd Functionまでが関数です。この部分をFunctionプロシージャとかユーザー定義関数と言ったりします。全体を通して実行すると3という値を出力します。

まず基本事項の説明をします。関数の用語として以下を解説します。

  • 関数名
  • 引数
  • 戻り値

関数名

関数名というのは関数の名前です。

上のコードではFunctionの後の「sample」が関数名となります。

このFunctionブロックはVBAの実行を行っても直接実行されません。

Subブロックの中で呼び出すことで中身が実行されます。

引数

引数(ひきすう)というのは関数に渡す値です。Functionの後に「sample(a As Integer)」とありますよね。

これは関数「sample」の引数がInteger型のaという変数ですよ。

という意味です。

引数はFunctionのブロックの中(End Functionまで)でInteger型のaという変数として振る舞います。

Subのブロックの中で

b = sample(2)

とありますね。これは関数sampleを使っているのですが、「(2)」と付いています。

この意味ですが、sampleという関数を呼び出したときにaに2を代入するという意味です。

こうして関数を呼び出して引数を渡すことで、Functionブロックの中でaにIntegerの2が代入された状態でFunctionの中身が実行されます。

戻り値

戻り値というのは呼び出し元に返す(戻す)値です。

Functionブロックの中で

sample = a + 1

とありますね。

これは引数として渡されたaという変数に1を足して、呼び出し元に戻り値として結果を返しなさいという意味です。

関数名 = 戻り値

という書き方をします。

Subブロックの中で

b = sample(2)

とありますね。これは引数として2を渡して関数を実行して、結果をbという変数に代入するという意味です。Functionの中身は引数のaに1を足すというだけの処理でした。

つまり2+1の結果として3という数値が変数bに代入されます。

塩ビ管の体積を求める【エクセル関数で求める場合】

各セルに次のように入力します。


E3: =((C3/2)^2)*3.14159

F3: =E3*D3*0.001

直径と長さはmmで指定して、体積はmlで出力されます。

円の面積は「半径×半径×π」、体積は「円の面積×柱の長さ」です。

0.001を掛けているのはmlで出力するための単位合わせです。

VBAで求める場合

コード入力欄に次のように入力します。

Function vol(a As Double, b As Double)
    vol = ((a / 2) ^ 2) * 3.14159 * b
End Function
Function convmm3(a As Double)
    convmm3 = a * 0.001
End Function
Sub calcVol()
    Dim a As Double
    Dim b As Double
    a = Range("C3").Value
    b = Range("D3").Value
    Range("G3").Value = convmm3(vol(a, b))
End Sub

解説していきます。

Function vol(a As Double, b As Double)
    vol = ((a / 2) ^ 2) * 3.14159 * b
End Function

今回はSubではなく、Functionで始まります。

SubとFunctionの違いは簡単に言うと処理をした後に値を呼び出し元に返すかどうかです。

Sub calcVol()の中で関数の結果が使いたいのでSubではなくFunctionを使います。

vol(a As Double, b As Double)の中のaとbは「引数」と言って、関数を使うときに関数に渡す値です。

今回はaに直径、bに長さを渡します。

関数名を関数の中で使うと呼び出し元に関数名のイコールの右側の値を返します。戻り値です。

今回は体積を呼び出し元に返しています。

vol = ((a / 2) ^ 2) * 3.14159 * b

の部分ですね。

Function convmm3(a As Double)
    convmm3 = a * 0.001
End Function

同様に立方ミリメートルmm3をミリリットルmlに変換している関数がこれです。

出力がmlの値になって呼び出し元に返されます。

Sub calcVol()
    Dim a As Double
    Dim b As Double
    a = Range("C3").Value
    b = Range("D3").Value
    Range("G3").Value = convmm3(vol(a, b))
End Sub

これがVBAの本体です。

aにシート上の直径、bにシート上の長さを格納して、G3セルに体積mlを返しています。

まずconvmm3()から見ていきます。

関数を使うときは定義した関数名の後に()をつけて呼び出します。

convmm3には立方ミリメートルの値が入ることになっていましたね?

なので入る予定の場所でさらに関数を呼び出します。

vol()関数です。

ここには直径と長さが入ります。

なのでaとbを渡します。

するとまずVBAはvol(a,b)を計算して、その結果をconvmm3に渡してくれます。

そしてconvmm3が実行されて結果がG3セルに格納されます。

定義したFunction関数はシート上でも使える

少しコラム的なことを書くと、VBAで定義したFunction関数はユーザー定義関数と呼ばれ、シート上で普通に他の関数のように呼び出すことができます。

H3: =vol(C3,D3)

I3: =convmm3(H3)

I3セルに体積mlが出力されます。

使い方次第では便利な機能です。

関数のスコープ

お気づきかと思いますが、

Function vol(a As Double, b As Double)

Function convmm3(a As Double)

では引数に同じaという文字を使っていますよね。

どっちもaで重複しているから、プログラムを書いたらいつどちらが有効になっているのだろう?と疑問に思いませんか?

それを管理しているのがスコープという概念です。

簡単に言うと、

変数や引数はその関数の中でだけ有効

ということです。

この管理手法のおかげで、vol関数のaはvol関数の中だけで有効だし、convmm3関数のaはconvmm3関数の中でだけ有効となります。

これによって重複問題がある程度解決します。

また引数にaを指定した場合、変数でaを定義しなおすとぐちゃぐちゃなコードになってよくないので、引数の名前と変数の名前は重複しないようにしたほうがいいでしょう。

Function convmm3(a As Double)

で引数にaを指定したのに関数内で

Dim a As Double

と書くのはやめておいたほうがいいという話です。

Sub calcVol()の中のaとbも他のFunctionの中のa,bとは区別されます。

関数を使うとコードがスッキリしてバグも少なくなる

極端な話、関数を使わずに、計算過程をすべてSubプロシージャ内に書いてしまってもプログラムは動きます。

ではなぜ関数を使うのか、というと、役割を分割したほうが見やすくなるからです。

関数化されていれば「この部分はこの計算をしているんだな」とわかりやすくなります。Subプロシージャ内でゴチャゴチャ書くとどこからどこまでが何をやっているのかわかりにくくなります。特に長いプログラムで顕著です。

役割は分割して関数化しましょう。見やすくなればそれだけ思わぬ勘違いも減り、バグも減ります。

まとめ

今回は関数に関して解説しました。

関数を使うことでコードが見やすくなります。

全部処理を一つのSub関数の中に書くより、機能ごとに切り出してFunction化して、Sub関数の中で呼び出したほうが、何をやっているかわかりやすくなります。

慣れて使えるようになると便利ですよ。