サーチ…
暗黙的かつ明示的な宣言
コードモジュールにモジュールの先頭にOption Explicit
が含まれていない場合、コンパイラは自動的に(暗黙的に)作成変数を使用します。それらは、デフォルトでVariant
型Variant
ます。
Public Sub ExampleDeclaration()
someVariable = 10 '
someOtherVariable = "Hello World"
'Both of these variables are of the Variant type.
End Sub
上記のコードでOption Explicit
が指定されている場合、 someVariable
およびsomeOtherVariable
必要なDim
ステートメントがないため、コードが中断します。
Option Explicit
Public Sub ExampleDeclaration()
Dim someVariable As Long
someVariable = 10
Dim someOtherVariable As String
someOtherVariable = "Hello World"
End Sub
コードモジュールでOption Explicitを使用して、すべての変数を確実に宣言することをお勧めします。
このオプションをデフォルトで設定する方法については、 VBAのベストプラクティスを参照してください。
変数
範囲
変数を宣言することができます(可視性レベルを上げる):
- プロシージャ・レベルでは、任意のプロシージャで
Dim
キーワードを使用します。 ローカル変数 。 - モジュールレベルでは、どのタイプのモジュールでも
Private
キーワードを使用します。 プライベートフィールド 。 - インスタンスレベルでは、どのタイプのクラスモジュールでも
Friend
キーワードを使用します。 友人のフィールド 。 - インスタンス・レベルでは、どのタイプのクラス・モジュールでも
Public
キーワードを使用します。 パブリックフィールド - 標準モジュールで
Public
キーワードを使用してグローバルにグローバル変数 。
変数は常に最小限のスコープで宣言する必要があります。グローバル変数を宣言するのではなく、プロシージャにパラメータを渡すことを優先します。
詳細については、 アクセス修飾子を参照してください。
ローカル変数
Dim
キーワードを使用してローカル変数を宣言します 。
Dim identifierName [As Type][, identifierName [As Type], ...]
宣言構文の[As Type]
部分はオプションです。これを指定すると、変数のデータ型が設定され、その変数に割り当てられるメモリ量が決まります。これはString
変数を宣言します:
Dim identifierName As String
型が指定されていない場合、型は暗黙的に型Variant
:
Dim identifierName 'As Variant is implicit
VBA構文では、1つのステートメントで複数の変数を宣言することもできます。
Dim someString As String, someVariant, someValue As Long
各変数([Variant]以外)に対して[As Type]
を指定する必要があることに注意してください。これは比較的一般的なトラップです:
Dim integer1, integer2, integer3 As Integer 'Only integer3 is an Integer.
'The rest are Variant.
静的変数
ローカル変数はStatic
でもStatic
ません。 VBAでは、 Static
キーワードを使用して、変数に前回プロシージャが呼び出されたときの値を「記憶」します。
Private Sub DoSomething()
Static values As Collection
If values Is Nothing Then
Set values = New Collection
values.Add "foo"
values.Add "bar"
End If
DoSomethingElse values
End Sub
ここでvalues
コレクションはStatic
ローカルとして宣言されています。これはオブジェクト変数であるため、 Nothing
初期化されます。宣言に続く条件は、オブジェクト参照が前にSet
かどうかを検証します。プロシージャが初めて実行される場合、コレクションは初期化されます。 DoSomethingElse
がアイテムを追加または削除している可能性があります。次回DoSomething
が呼び出されたときにコレクションに残ります。
オルタナティブ
VBAの
Static
キーワードを簡単に誤解することができます- 特に 、通常は他の言語で働く経験豊かなプログラマーで。多くの言語では、クラスメンバ(フィールド、プロパティ、メソッドなど)をインスタンスではなくタイプにするためにstatic
が使用されています 。static
コンテキスト内のコードは、 インスタンスコンテキスト内のコードを参照できません。 VBAのStatic
キーワードは、大きく違うものを意味します。
しばしば、 Static
ローカルは、モジュールレベルのPrivate
変数(フィールド)として実装することもできますが、変数を最小限のスコープで宣言する必要があります。あなたの本能を信頼し、好きな方を使う - どちらもうまくいきますが、それが何を理解することなくStatic
を使用すると、面白いバグにつながる可能性があります。
暗い対私的
Dim
キーワードは、プロシージャとモジュールレベルでは合法です。モジュールレベルでのその使用法は、 Private
キーワードの使用と同じです:
Option Explicit
Dim privateField1 As Long 'same as Private privateField2 as Long
Private privateField2 As Long 'same as Dim privateField2 as Long
Private
キーワードは、モジュールレベルでのみ有効です。これはDim
をローカル変数に予約し、モジュール変数をPrivate
で宣言します。特にパブリックメンバを宣言するために使用しなければならない対照的なPublic
キーワードを使用します。代わりにDim
どこでも使用してください。 一貫性が重要です。
"プライベートフィールド"
- 使用しています
Private
モジュールレベルの変数を宣言します。 - 使うのですか
Dim
ローカル変数を宣言します。 -
Dim
を使用してモジュールレベルの変数を宣言しないでください 。
"どこにでも暗い"
- 使うのですか
Dim
ローカル/プライベート何かを宣言します。 -
Private
を使用してモジュールレベルの変数を宣言しないでください 。 -
Public
フィールドの宣言を避ける *
*一般的には、とにかくPublic
またはGlobal
フィールドを宣言しないでください。
フィールド
モジュール本体の上部にある宣言セクションのモジュールレベルで宣言された変数は、 フィールドです。 標準モジュールで宣言されたPublic
フィールドは、 グローバル変数です 。
Public PublicField As Long
グローバルスコープの変数は、宣言されているプロジェクトを参照する他のVBAプロジェクトを含め、どこからでもアクセスできます。
変数をグローバル/パブリックにするには、プロジェクト内からしか見ることができないようにするには、 Friend
修飾子を使用します。
Friend FriendField As Long
これは、他のVBAプロジェクトがアドインプロジェクトを参照し、パブリックAPIを使用できるというアドインでは特に便利です。
Friend FriendField As Long 'public within the project, aka for "friend" code
Public PublicField As Long 'public within and beyond the project
Friendフィールドは、標準モジュールでは使用できません。
インスタンスフィールド
クラスモジュール( ThisWorkbook
、 ThisDocument
、 Worksheet
、 UserForm
、 クラスモジュールを含む)の本体の上部にある宣言セクションのモジュールレベルで宣言された変数は、 インスタンスフィールドです。 インスタンスが存在する限り存在します周りのクラス。
'> Class1
Option Explicit
Public PublicField As Long
'> Module1
Option Explicit
Public Sub DoSomething()
'Class1.PublicField means nothing here
With New Class1
.PublicField = 42
End With
'Class1.PublicField means nothing here
End Sub
カプセル化フィールド
インスタンスデータはしばしばPrivate
に保たれ、 カプセル化されたダビングされます 。プライベートフィールドは、 Property
プロシージャを使用して公開することができます。呼び出し元への書き込みアクセスを与えずにプライベート変数を公開するために、クラスモジュール(または標準モジュール)はProperty Get
メンバを実装します:
Option Explicit
Private encapsulated As Long
Public Property Get SomeValue() As Long
SomeValue = encapsulated
End Property
Public Sub DoSomething()
encapsulated = 42
End Sub
クラス自体はカプセル化された値を変更することができますが、呼び出し元のコードはPublic
メンバー(および呼び出し元が同じプロジェクトにある場合はFriend
メンバー)にのみアクセスできます。
発信者が以下を変更できるようにするには:
- カプセル化された値であるモジュールは、
Property Let
メンバーを公開します。 - カプセル化されたオブジェクト参照で、モジュールは
Property Set
メンバを公開します。
定数(Const)
アプリケーションで決して変更されない値がある場合は、名前付き定数を定義してリテラル値の代わりに使用できます。
Constは、モジュールまたはプロシージャ・レベルでのみ使用できます。つまり、変数の宣言コンテキストは、クラス、構造体、モジュール、プロシージャ、またはブロックでなければならず、ソースファイル、名前空間、またはインタフェースにすることはできません。
Public Const GLOBAL_CONSTANT As String = "Project Version #1.000.000.001"
Private Const MODULE_CONSTANT As String = "Something relevant to this Module"
Public Sub ExampleDeclaration()
Const SOME_CONSTANT As String = "Hello World"
Const PI As Double = 3.141592653
End Sub
Constant型を指定することをお勧めしますが、厳密には必須ではありません。タイプを指定しないと正しいタイプになります:
Public Const GLOBAL_CONSTANT = "Project Version #1.000.000.001" 'Still a string
Public Sub ExampleDeclaration()
Const SOME_CONSTANT = "Hello World" 'Still a string
Const DERIVED_CONSTANT = SOME_CONSTANT 'DERIVED_CONSTANT is also a string
Const VAR_CONSTANT As Variant = SOME_CONSTANT 'VAR_CONSTANT is Variant/String
Const PI = 3.141592653 'Still a double
Const DERIVED_PI = PI 'DERIVED_PI is also a double
Const VAR_PI As Variant = PI 'VAR_PI is Variant/Double
End Sub
これは定数に固有であり、タイプを指定しない変数とは対照的に、バリアント型の結果となることに注意してください。
定数を明示的にStringとして宣言することは可能ですが、固定幅の文字列構文を使用して定数を文字列として宣言することはできません
'This is a valid 5 character string constant
Const FOO As String = "ABCDE"
'This is not valid syntax for a 5 character string constant
Const FOO As String * 5 = "ABCDE"
アクセス修飾子
Dim
ステートメントは、ローカル変数用に予約する必要があります。モジュールレベルでは、明示的なアクセス修飾子を使用することをお勧めします。
-
Private
フィールドのPrivate
。プライベートフィールドは、宣言されたモジュール内でしかアクセスできません。 -
Public
フィールドとグローバル変数のパブリック。任意の呼び出しコードからアクセスできます。 - プロジェクト内のパブリック変数は
Friend
ですが、他の参照用VBAプロジェクトにはアクセスできません(アドインに関連しています) -
Global
は、標準モジュールのPublic
フィールドにも使用できますが、クラスモジュールでは不正です。代わりにPublic
修飾子を使用することをお勧めします。この修飾子は、プロシージャにとっても合法ではありません。
アクセス修飾子は、変数およびプロシージャにも同様に適用できます。
Private ModuleVariable As String
Public GlobalVariable As String
Private Sub ModuleProcedure()
ModuleVariable = "This can only be done from within the same Module"
End Sub
Public Sub GlobalProcedure()
GlobalVariable = "This can be done from any Module within this Project"
End Sub
オプションプライベートモジュール
公開パラメータなし標準モジュールのSub
プロシージャは、マクロとして公開され、ホスト文書のコントロールおよびキーボードショートカットにアタッチできます。
逆に、標準モジュールのpublic Function
プロシージャは、ホストアプリケーション内のユーザ定義関数(UDF)として公開されます。
標準モジュールの上部にOption Private Module
を指定すると、メンバーがマクロおよびUDFとしてホストアプリケーションに公開されなくなります。
タイプヒント
タイプヒントはあまりお勧めできません。それらは存在し、歴史的および後方互換性の理由からここに文書化されています。代わりにAs [DataType]
構文を使用する必要がありAs [DataType]
。
Public Sub ExampleDeclaration()
Dim someInteger% '% Equivalent to "As Integer"
Dim someLong& '& Equivalent to "As Long"
Dim someDecimal@ '@ Equivalent to "As Currency"
Dim someSingle! '! Equivalent to "As Single"
Dim someDouble# '# Equivalent to "As Double"
Dim someString$ '$ Equivalent to "As String"
Dim someLongLong^ '^ Equivalent to "As LongLong" in 64-bit VBA hosts
End Sub
タイプヒントは大幅にコードの可読性を低下させ、従来の奨励ハンガリアン記法 も読みやすさを妨げます。
Dim strFile$
Dim iFile%
代わりに、使用法に近い変数を宣言し、使用したものの名前を型の後ではなく名前にします。
Dim path As String
Dim handle As Integer
型ヒントは、特定の型を強制するためにリテラルでも使用できます。デフォルトでは、32,768より小さい数値リテラルはInteger
リテラルとして解釈されますが、ヒントタイプを使用してそれを制御できます。
Dim foo 'implicit Variant
foo = 42& ' foo is now a Long
foo = 42# ' foo is now a Double
Debug.Print TypeName(42!) ' prints "Single"
型ヒントは、明示的な型で宣言された変数に代入されるか、またはパラメータとして渡されたときに暗黙的に適切な型に変換されるため、通常はリテラルには必要ありません。暗黙的な変換は、明示的な型変換関数の1つを使用して回避できます。
'Calls procedure DoSomething and passes a literal 42 as a Long using a type hint
DoSomething 42&
'Calls procedure DoSomething and passes a literal 42 explicitly converted to a Long
DoSomething CLng(42)
文字列を返す組み込み関数
文字列を処理する組み込み関数の大部分は、 Variant
を返す緩やかに型付けされたバージョンと、 String
を返す厳密に型指定されたバージョン( $
終わる)の2つのバージョンがあります。返り値をVariant
に代入している場合を除き、 String
を返すバージョンを選ぶ必要があります。そうでなければ、返り値の暗黙の変換があります。
Debug.Print Left(foo, 2) 'Left returns a Variant
Debug.Print Left$(foo, 2) 'Left$ returns a String
これらの機能は次のとおりです。
- VBA.Conversion.Error - > VBA.Conversion.Error $
- VBA.Conversion.Hex - > VBA.Conversion.Hex $
- VBA.Conversion.Oct - > VBA.Conversion.Oct $
- VBA.Conversion.Str - > VBA.Conversion.Str $
- VBA.FileSystem.CurDir - > VBA.FileSystem.CurDir $
- VBA。[_ HiddenModule] .Input - > VBA。[_ HiddenModule] .Input $
- VBA。[_ HiddenModule] .InputB - > VBA。[_ HiddenModule] .InputB $
- VBA.Interaction.Command - > VBA.Interaction.Command $
- VBA.Interaction.Environ - > VBA.Interaction.Environ $
- VBA.Strings.Chr - > VBA.Strings.Chr $
- VBA.Strings.ChrB - > VBA.Strings.ChrB $
- VBA.Strings.ChrW - > VBA.Strings.ChrW $
- VBA.Strings.Format - > VBA.Strings.Format $
- VBA.Strings.LCase - > VBA.Strings.LCase $
- VBA.Strings.Left - > VBA.Strings.Left $
- VBA.Strings.LeftB - > VBA.Strings.LeftB $
- VBA.Strings.LTtrim - > VBA.Strings.LTrim $
- VBA.Strings.Mid - > VBA.Strings.Mid $
- VBA.Strings.MidB - > VBA.Strings.MidB $
- VBA.Strings.Right - > VBA.Strings.Right $
- VBA.Strings.RightB - > VBA.Strings.RightB $
- VBA.Strings.RTrim - > VBA.Strings.RTrim $
- VBA.Strings.Space - > VBA.Strings.Space $
- VBA.Strings.Str - > VBA.Strings.Str $
- VBA.Strings.String - > VBA.Strings.String $
- VBA.Strings.Trim - > VBA.Strings.Trim $
- VBA.Strings.UCase - > VBA.Strings.UCase $
これらは関数のエイリアスであり、 型ヒントではないことに注意してください。 Left
関数は隠れたB_Var_Left
関数に対応し、 Left$
は隠れたB_Str_Left
関数に対応します。
VBAの非常に初期のバージョンでは、 $
記号は許可された文字ではなく、関数名は角括弧で囲む必要がありました。 Word Basicでは、$で終わった文字列を返す関数が数多くありました。
固定長文字列の宣言
VBAでは、文字列は特定の長さで宣言できます。宣言されている長さに維持されるように自動的にパディングまたは切り捨てられます。
Public Sub TwoTypesOfStrings()
Dim FixedLengthString As String * 5 ' declares a string of 5 characters
Dim NormalString As String
Debug.Print FixedLengthString ' Prints " "
Debug.Print NormalString ' Prints ""
FixedLengthString = "123" ' FixedLengthString now equals "123 "
NormalString = "456" ' NormalString now equals "456"
FixedLengthString = "123456" ' FixedLengthString now equals "12345"
NormalString = "456789" ' NormalString now equals "456789"
End Sub
静的変数を使用する場合
ローカルで宣言されたStatic変数は破棄されず、Subプロシージャが終了したときに値が失われません。それ以降のプロシージャの呼び出しでは、再初期化や割り当ては必要ありませんが、記憶された値は「0」にすることもできます。
これらは、繰り返し呼び出される 'ヘルパー'サブオブジェクトにレイトバインドするときに特に便利です。
スニペット1:多くのワークシートにわたるScripting.Dictionaryオブジェクトの再利用
Option Explicit
Sub main()
Dim w As Long
For w = 1 To Worksheets.Count
processDictionary ws:=Worksheets(w)
Next w
End Sub
Sub processDictionary(ws As Worksheet)
Dim i As Long, rng As Range
Static dict As Object
If dict Is Nothing Then
'initialize and set the dictionary object
Set dict = CreateObject("Scripting.Dictionary")
dict.CompareMode = vbTextCompare
Else
'remove all pre-existing dictionary entries
' this may or may not be desired if a single dictionary of entries
' from all worksheets is preferred
dict.RemoveAll
End If
With ws
'work with a fresh dictionary object for each worksheet
' without constructing/destructing a new object each time
' or do not clear the dictionary upon subsequent uses and
' build a dictionary containing entries from all worksheets
End With
End Sub
スニペット2: VBScript.RegExpオブジェクトを後でバインドするワークシートUDFを作成する
Option Explicit
Function numbersOnly(str As String, _
Optional delim As String = ", ")
Dim n As Long, nums() As Variant
Static rgx As Object, cmat As Object
'with rgx as static, it only has to be created once
'this is beneficial when filling a long column with this UDF
If rgx Is Nothing Then
Set rgx = CreateObject("VBScript.RegExp")
Else
Set cmat = Nothing
End If
With rgx
.Global = True
.MultiLine = True
.Pattern = "[0-9]{1,999}"
If .Test(str) Then
Set cmat = .Execute(str)
'resize the nums array to accept the matches
ReDim nums(cmat.Count - 1)
'populate the nums array with the matches
For n = LBound(nums) To UBound(nums)
nums(n) = cmat.Item(n)
Next n
'convert the nums array to a delimited string
numbersOnly = Join(nums, delim)
Else
numbersOnly = vbNullString
End If
End With
End Function
* UDFで500Kの行を満たす経過時間: - Dim rgx Asオブジェクト :148.74秒 - スタティックrgxオブジェクト :26.07秒 * これらは相対比較のみを考慮してください。あなた自身の結果は複雑さと
実行される操作の範囲。
ワークブックの存続期間中はUDFは一度も計算されません。不揮発性UDFであっても、参照する範囲内の値が変更されるたびに再計算されます。後続の再計算イベントが発生するたびに、静的に宣言された変数の利点が増えます。
- 静的変数は、宣言され割り当てられたプロシージャまたは関数ではなく、モジュールの存続期間中に使用できます。
- 静的変数はローカルでのみ宣言できます。
- 静的変数は、プライベートモジュールレベル変数の同じプロパティの多くを保持しますが、スコープは制限されています。
関連資料: 静的(Visual Basic)