連載

プロフェッショナルVB.NETプログラミング

第4回 変数スコープと文字列関数

(株)ピーデー
川俣 晶
2002/04/23

Page1 Page2

変数のスコープ

 VB 6では、メソッド内で定義された変数は、メソッド内全域で有効であった。そのため、Forループの内側で宣言した変数をForループの外側で参照しても問題はない。また、宣言された場所に関係なく、メソッドを脱出するまでその内容は有効であり、値を累積することも可能だった。このことを示すサンプル・ソースを以下に示す。

 1: Private Sub Form_Load()
 2:   Dim a As Integer
 3:   For i = 0 To 9
 4:     Dim b As Integer
 5:     a = a + 1
 6:     b = b + 1
 7:     Debug.Print a, b
 8:   Next
 9:   Debug.Print a, b
10: End Sub
変数のスコープを示すVB 6のサンプル・プログラム3

 これを実行すると以下のようになる。

1             1
2             2
3             3
4             4
5             5
6             6
7             7
8             8
9             9
10            10
10            10
サンプル・プログラム3の実行結果

 これをVB.NETに書き換えたものを以下に示す。

 1: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
 2:   Dim a As Integer
 3:   Dim i As Integer
 4:   For i = 0 To 9
 5:     Dim b As Integer
 6:     a = a + 1
 7:     b = b + 1
 8:     Trace.Write(a)
 9:     Trace.Write(", ")
10:     Trace.WriteLine(b)
11:   Next
12:   Trace.Write(a)
13:   Trace.Write(", ")
14:   'Trace.WriteLine(b) '名前 'b' は宣言されていません。
15: End Sub
サンプル・プログラム12をVB.NETで書き換えたサンプル・プログラム4

 これを実行すると以下のようになる。

1, 1
2, 2
3, 3
4, 4
5, 5
6, 6
7, 7
8, 8
9, 9
10, 10
10,
サンプル・プログラム4の実行結果

 ほとんど同じように見えるが、14行目がエラーになる点に注意が必要である。VB.NETでは、変数はスコープを持っており、Forループなどブロック構造を表記する構文の中で宣言された変数は、そのブロック構造の内側からしか利用することができない。しかし、変数にスコープを持つほかの主要な言語(C/C++/Java/C#など)とは異なり、メソッドなどを脱出するまで変数は有効という特徴は継承されており、ブロック内で宣言された変数で値を累積していくことができる。この点で、VB.NETのスコープの概念は、VB 6と異なるだけでなく、C/C++/Java/C#などとも異なるため、注意して扱う必要がある。

 値を累積したくない場合は、変数宣言の直後に変数の値を初期化するコードを必ず書き込むようにすると、意図しない動作を防止できる。

文字列関連関数の相違

 VB 6には文字列関連の関数に2つのバージョンを持つものがあった。例えば、Chr関数とChr$関数は別個の関数である。“$”の付くものは文字列型を扱い、“$”の付かないものはVariant型を扱う。この結果、文字列ではないデータを扱ったときに挙動が異なる場合があった。以下はこのような関数の一例としてLeft関数とLeft$関数を扱った例である。

1: Private Sub Form_Load()
2:   Dim v As Variant, r As Variant
3:   v = Null
4:   r = Left(v, 3)
5:   Debug.Print TypeName(r)
6:   v = "ABCDEF"
7:   r = Left$(v, 3)
8:   Debug.Print TypeName(r)
9: End Sub
Left関数とLeft$関数を使用したVB 6のサンプル・プログラム5

 これを実行すると以下のようになる。

Null
String
サンプル・プログラム5の実行結果

 Left関数にNull値を渡すことは合法で、結果はNull値になる。しかし、Left$関数にNull値を渡すことはできない。

 これをVB.NET用に書き換えたのが以下のサンプル・ソースである。

1: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
2:   Dim v As Object, r As Object
3:   v = Nothing
4:   r = Microsoft.VisualBasic.Left(v, 3)
5:   Trace.WriteLine(TypeName(r))
6:   v = "ABCDEF"
7:   r = Microsoft.VisualBasic.Left$(v, 3)
8:   Trace.WriteLine(TypeName(r))
9: End Sub
サンプル・プログラム14をVB.NETで書き換えたサンプル・プログラム6

 これを実行すると以下のようになる。

String
String
サンプル・プログラム6の実行結果

 VariantがObjectに、NullがNothingになるのは、一種のお約束である。さて肝心の結果だが、VB 6の場合とは異なっていることが分かるだろう。VB 6では2種類あった文字列関数は、VB.NETでは1種類しか存在しない。Variant型を返す関数は存在しないため、Left関数の結果は常に文字列になる。構文的にLeftのほかにLeft$という名前を記述することは可能だが、これは型指定文字としての$記号が付加されているだけで、別の関数の呼び出しになるわけではない(なお、Leftというキーワードのプロパティなどがあり紛らわしいときは、このサンプル・ソースのように、LeftのかわりにMicrosoft.VisualBasic.Leftといった長い完全修飾名の記述が必要となる場合がある)。その結果、Null(Nothing)値を引数に取った場合のLeft関数の挙動に相違が生じているわけである。文字列関連関数で、文字列以外の値を扱うことはめったにないかもしれないが、意図せざるバグによりそれを処理してしまっている可能性もある。もし、VB.NETでプログラミングしていて、文字列関連の挙動がVB 6と異なるときは、チェックしてみる価値があるだろう。

まとめ

 VB.NETは、VB 6と比較してあちこち変わっていることがお分かりいただけたと思うが、決してVB.NETはVBの文法で書くC#ではない。VBらしいお約束が残されていて、C#とは異なる動作を見せる機能もある。そのため、VB 6とC#を知っているからといって、VB.NETを勉強せずに、すぐに使いこなせるというわけでもない。十分に注意しよう。

 次回は日付と時刻の扱いについて解説したいと考えている。

 では次回もまた会おう。End of Article


 INDEX
  連載 プロフェッショナルVB.NETプログラミング
  第4回 変数スコープと文字列関数
    1.ランダム・ファイルとVBFixedString属性 
  2.変数のスコープ
 
「プロフェッショナルVB.NETプログラミング」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間