수색…


암시 적 및 명시 적 선언

코드 모듈에 모듈 상단에 Option Explicit 가 없으면 컴파일러는 자동으로 (즉, "암시 적으로") 변수를 사용합니다. 변수 유형 Variant 가 기본값이됩니다.

Public Sub ExampleDeclaration()    

    someVariable = 10                  ' 
    someOtherVariable = "Hello World"
    'Both of these variables are of the Variant type.

End Sub

위의 코드에서 Option Explicit 가 지정되면 someVariablesomeOtherVariable 필요한 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 구문은 단일 문에서 여러 변수 선언을 지원합니다.

Dim someString As String, someVariant, someValue As Long

[As Type] 은 각 변수 ( 'Variant'이외의 변수)에 대해 지정해야합니다. 이것은 비교적 일반적인 트랩입니다.

Dim integer1, integer2, integer3 As Integer 'Only integer3 is an Integer. 
                                            'The rest are Variant.

정적 변수

지역 변수는 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 멤버를 선언하기 위해 반드시 사용해야하는 대조되는 Public 키워드를 사용합니다. 또는 Dim 사방에 사용하십시오 - 중요한 것은 일관성입니다 .

"사유지"

  • 사용하십니까 Private 모듈 수준 변수를 선언 할 수 있습니다.
  • 사용하십니까 Dim 로컬 변수를 선언 할 수 있습니다.
  • Dim 을 사용하여 모듈 수준 변수를 선언 하지 마십시오 .

"어디에서나 어둡게"

  • 사용하십니까 Dim 지역 개인 아무것도 / 선언.
  • Private 을 사용하여 모듈 수준 변수를 선언 하지 마십시오 .
  • Public 입력란을 선언하지 마십시오 . *

* 일반적으로 Public 또는 Global 입력란은 신고하지 않아야합니다.


전지

모듈 본문 상단의 선언 섹션 에있는 모듈 수준에서 선언 된 변수는 필드 입니다. 표준 모듈 에서 선언 된 Public 필드는 전역 변수입니다 .

Public PublicField As Long

전역 범위가있는 변수는 선언 된 프로젝트를 참조하는 다른 VBA 프로젝트를 포함하여 어디서나 액세스 할 수 있습니다.

프로젝트 내에서만 볼 수있는 변수 global / public을 만들려면 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

친구 필드는 표준 모듈에서 사용할 수 없습니다.


인스턴스 필드

(포함 클래스 모듈의 본체 상단의 선언 섹션에서, 모듈 수준에서 선언 된 변수 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 프로 시저를 사용하여 노출 할 수 있습니다. 호출자에게 쓰기 권한을 부여하지 않고 private 변수를 공개적으로 노출 시키려면 클래스 모듈 (또는 표준 모듈)이 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

상수 유형을 지정하는 것이 우수 사례로 간주 될 수 있지만 엄격하게 필수는 아닙니다. 형식을 지정하지 않으면 올바른 형식이됩니다.

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

이것은 Constants에만 해당되며 Variant 유형의 결과가 Variant 유형으로 지정되지 않은 변수와는 대조적입니다.

상수를 문자열로 명시 적으로 선언 할 수는 있지만 고정 폭 문자열 구문을 사용하여 상수를 문자열로 선언 할 수는 없습니다

'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 필드에 대한 비공개. 선언 된 모듈 내에서만 액세스 할 수 있습니다.
  • 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 프로 시저는 매크로로 표시되며 호스트 문서의 컨트롤과 키보드 바로 가기에 첨부 할 수 있습니다.

반대로 표준 모듈의 공용 Function 프로 시저는 호스트 응용 프로그램에서 사용자 정의 함수 (UDF)로 표시됩니다.

표준 모듈의 맨 위에 Option Private Module 을 지정하면 멤버가 매크로 및 UDF로 호스트 응용 프로그램에 노출되지 않습니다.

유형 힌트

타입 힌트는 크게 권장하지 않습니다. 이전 및 이전 버전과의 호환성을 이유로 존재하며 여기에 설명되어 있습니다. 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"

형식 힌트는 보통 명시 적 형식으로 선언 된 변수에 할당되거나 매개 변수로 전달 될 때 암시 적으로 적절한 형식으로 변환되므로 리터럴에 필요하지 않습니다. 암시 적 변환은 명시 적 유형 변환 함수 중 하나를 사용하여 피할 수 있습니다.

'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 을 반환하는 강력한 형식의 버전 ( $ 끝나는)의 두 가지 버전으로 제공됩니다. 반환 값을 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'으로 원할 수 있지만 재 초기화 또는 할당이 필요하지 않습니다.

이것은 반복적으로 호출되는 '도우미'하위에 객체를 늦게 바인딩 할 때 특히 유용합니다.

Snippet 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

static_UDF
50 만 개 행을 채우는 정적 객체가있는 UDF의 예

* 경과 시간이 UDF로 500K 행을 채 웁니다.
- Dim rgx를 객체로 사용 : 148.74 초
- 정적 인 rgx 개체로 : 26.07 초
* 이들은 상대적 비교를 위해서만 고려되어야합니다. 자신의 결과는 복잡성 및
수행 된 작업의 범위.

통합 문서의 수명 기간 동안에는 UDF가 한 번 계산되지 않습니다. 비 휘발성 UDF조차도 참조하는 범위 내의 값이 변경 될 때마다 다시 계산됩니다. 이후의 각 재 계산 이벤트는 정적으로 선언 된 변수의 이점을 증가시킵니다.

  • 정적 변수는 모듈 수명 기간 동안 사용할 수 있으며 선언되고 할당 된 프로 시저 또는 함수는 사용할 수 없습니다.
  • 정적 변수는 로컬에서만 선언 할 수 있습니다.
  • 정적 변수는 개인 모듈 수준 변수의 동일한 속성을 많이 포함하지만 범위는 제한적입니다.

관련 참조 : 정적 (Visual Basic)



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow