修正候補: ステートメントの最後


メッセージの「ステートメント」とは、Dimステートメントとか、For Nextステートメントなどのステートメントではなく、「1行分の命令」という意味だと思います。VBAでは、1つの完結した命令を1行に書くのが原則です。この「ステートメントの最後」というエラーは、要するに「その行の命令は、何か変だよ」という程度の意味にお考えください。たとえば、下図のようなケースでも、このエラーが発生します。

おそらく「Range("A1") = 100」のつもりで「=」を入力し忘れたのでしょう。こんなとき「修正候補: 代入演算子がありません」みたいなエラーを表示してくれれば分かりやすいのですが、VBAは「Range("A1") までは理解できる。その後は普通ピリオドとか演算子とかがくるはずなのに・・・理解できた命令(ステートメント)Range("A1") の後ろは、意味がわりませ~ん」と判断したんでしょうね。たぶん(^^;

また、このエラーは、括弧を付けなければいけないところで、括弧が不足しているケースでも発生します。

上図は、Book1.xlsを開いて、そのブックをオブジェクト変数wbに格納しようとしています。このように、メソッドや関数の返り値を利用する場合は、引数を括弧で囲むのがVBAのルールです。VBAの括弧ルールに関しては、下記を参照してください。

マクロとVBAのテクニック「括弧が必要な場合」

メソッドの括弧だけでなく、プロシージャの括弧が足りない場合にも発生します。

別のプロシージャを呼び出すには、2通りの方法があります。1つは、ただプロシージャ名を書くだけです。

Sub Sample1()
    Sample2 "tanaka"    ''正常に動作します
End Sub

Sub Sample2(msg As String)
    MsgBox msg
End Sub

もうひとつは、Callステートメントを使う方法です。

Sub Sample1()
    Call Sample2("tanaka")    ''正常に動作します
End Sub

Sub Sample2(msg As String)
    MsgBox msg
End Sub

呼び出すプロシージャに引数を渡す場合、Callステートメントを使わないときは引数を括弧で囲みません。対して、Callステートメントを使うときは、引数を括弧で囲みます。

他のプロシージャを呼び出すときの、この括弧ルールは少々ややこしいです。Callステートメントを使うときは、必ず括弧が必要です。括弧がないとエラーになります。しかし、Callステートメントを使わないときは、括弧を付けてもエラーにはなりません。

Sub Sample1()
    Sample2 ("tanaka")    ''正常に動作します
End Sub

Sub Sample2(msg As String)
    MsgBox msg
End Sub

ややこしいですね。でも心配はいりません。他のプロシージャを呼び出すときは必ずCallステートメントを使うと決めておけばいいんです。Callステートメントは、他のプロシージャを呼び出すためのステートメントです。コード中に「Call ○○」と書かれていたら、それは「○○プロシージャを呼び出している」とコードを見ただけですぐ理解できます。Callステートメントを省略して、ただ「○○」と書いてあったら、それが何の意味なのかを考えなければなりません。どちらが可読性に優れいているかは言うまでもありませんね。他のプロシージャを呼び出すときは必ずCallステートメントを使う引数を渡すときは括弧で囲む。この、とてもシンプルな2つのルールを守ればいいですね。

なお、Callステートメントを使わないで他プロシージャを呼び出すとき、引数を括弧で囲むのと囲まないのでは、実は微妙に動作が異なります。本コンテンツとは関係のない話なので詳しくは書きませんが、興味のある方は、次のコードを実行して違いを確認してください。

Sub Sample1()
    Dim buf As String
    buf = "tanaka"
    Sample2 buf
    MsgBox buf
End Sub
Sub Sample2(ByRef msg As String)
    msg = "suzuki"
End Sub
Sub Sample1()
    Dim buf As String
    buf = "tanaka"
    Sample2 (buf)
    MsgBox buf
End Sub
Sub Sample2(ByRef msg As String)
    msg = "suzuki"
End Sub

Callステートメントを使わないで他プロシージャを呼び出すとき、呼び出し先の引数定義がByRef(参照渡し)だったとしても、引数を括弧で囲むとByVal(値渡し)で渡されます。まぁ、こんな使い方は、ほとんどしませんけど。