2013年12月14日

vba:関数内の一部分のみのスコープを持つ変数

もちろんvbaの仕様は変えられないので「変数」では出来ないけど、オブジェクトを使えばWithステートメントの中だけ有効にすることが出来るので、そこに動的にプロパティを追加すればタイトルに近いことが出来る。
具体的にはJavascriptで同じ様なテーマで、連想配列をWithで使う以下の様な方法を書いてたサイトがあったので、これをvbaで実現することにした。
with ({a:0}) {
この中では a は有効。
}
withを抜けると a は参照不可。

そしてvbaで連想配列を返す関数は以下の通り。
Function TempDim(ByVal Dimension As String, Optional Parent As Object) As Object
'Dimension:変数宣言をカンマ区切りの文字列で行う。ex.)"TempNo,Name"
'Parent:ネストする場合、子のWith内では親の連想配列が参照できないので、
' パラメータとして渡す。
Dim sc As Object
Dim hash As Object
Dim i As Long
Dim v() As String
Set sc = CreateObject("ScriptControl")
sc.Language = "JScript"
sc.AddCode "function SetValue(hash, key, value) " & _
"{j=hash ? hash : {};j[key]=value;return j;}"
v = Split(Dimension, ",")
For i = LBound(v) To UBound(v)
Set hash = sc.CodeObject.SetValue(hash, v(i), Null)
Next i
Set hash = sc.CodeObject.SetValue(hash, "Me", hash)
If Not Parent Is Nothing Then
Set hash = sc.CodeObject.SetValue(hash, "Parent", Parent)
End If
Set TempDim = hash
End Function


そして以下の様に使用する。
宣言した名前はプロパティになるので、With内で頭にピリオドを付けて使用する。
With TempDim("i,j")
.i = 1
.j = 1
Do Until .i > 3
Debug.Print "親ループ i="; .i
Debug.Print "親ループ j="; .j
With TempDim("i", .Me) 'Meは自身を参照する
.i = 1
Do Until .i > 3
Debug.Print "子ループ i="; .i
.i = .i + 1
'Parentはパラメータで渡された親の連想配列
.Parent.j = .Parent.j + 1
Loop
End With
.i = .i + 1
Loop
End With

使用上の注意
  • For文のカウンターには使えない。
    For文のカウンターは変数でなければならず、この方法ではオブジェクトのプロパティとなるため使えない。
  • プロパティ名は大文字小文字が区別される。
    JScriptの機能で連想配列を実現してるのでJScriptの制限を受ける。VBエディタの変数名の自動修正機能に注意!
  • Variant型のみ
    連想配列に型が無いためそうなる。あと上の関数では初期値をNULLにしている。
posted by 忘却の達人 at 13:06| Comment(0) | TrackBack(0) | vba | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
この記事へのトラックバックURL
http://blog.seesaa.jp/tb/382666232

この記事へのトラックバック