VBA 수수께끼 사양 : For Each에서 지정하는 변수는 변수적이면 무엇이든 지정할 수 있으며 루프마다 평가됩니다.
16516 단어 VBA
소개
VBA에서 For Each 문을 사용하면 배열과 열거 가능한 개체의 요소를 반복할 수 있습니다.
이때 루프마다 각 요소가 저장되는 변수(아래 코드의 element
.
For Each element In group
statements
Next
각...Next 문(VBA) | Microsoft Docs
For Each...Next 문 사용(VBA) | Microsoft Docs
"변수적인 것"의 정의
이 기사에서 "변수적인 것"은 다음과 같이 정의됩니다.
ByRef が指定されたプロシージャの引数に指定したとき、プロシージャ内で変更された内容が反映される任意の式
구체적으로는, 임의의 변수, 배열의 요소, 유저 정의형의 필드등이 해당합니다.
프로퍼티로서 동작하는 것 ( Property
프로시저로 정의된 것, 표준 모듈 이외의 모듈의 Public
의 변수를 .
경유로 액세스 한 것)는 포함하지 않습니다.
변수적인 것Type SampleUDT
Value As Variant
End Type
Public varPublic As Variant
Sub VariableExpression()
Dim arr() As Variant
arr = VBA.[_HiddenModule].Array()
'任意の変数。
Dim varLocal As Variant
For Each varLocal In arr
Next varLocal
For Each varPublic In arr
Next varPublic
'配列の要素。
Dim varArr(0 To 0) As Variant
For Each varArr(0) In arr
Next varArr(0)
'ユーザー定義型のフィールド。
Dim varUdt As SampleUDT
For Each varUdt.Value In arr
Next varUdt.Value
'以下はNG
'For Each propValue In arr
'Next
End Sub
Public Property Get propValue() As Variant
End Property
Public Property Let propValue(inValue As Variant)
End Property
실제로 확인
「배열의 요소」를 지정해 For Each
루프를 실시하는 샘플 코드입니다.
Sub SampleForEach()
'VBA.Collection を新規インスタンスして、適当に中身を設定する。
Dim col As VBA.Collection
Set col = New VBA.Collection
'文字列・整数・小数・日付・オブジェクト・Null を設定。
col.Add "ABC"
col.Add 123
col.Add 3.14
col.Add VBA.DateTime.DateSerial(2021, 3, 27)
col.Add Err
col.Add Null
'Variant 型の配列を宣言し、VBA.Collection の要素数 + 1 だけ領域を確保する。
Dim arr() As Variant
ReDim arr(1 To col.Count() + 1)
'配列の末尾に「Hoge」を設定する。
arr(UBound(arr)) = "Hoge"
Dim i As Long
i = LBound(arr)
For Each arr(i) In col
i = i + 1
Next arr(i)
Stop
End Sub
이 코드에는 For Each arr(i) In col
라는 줄이 있으며 element
표시합니다.
실제로 For Each
의 시점에서의 로컬 윈도우의 내용을 확인하면, 이하의 화상과 같이 되어 있습니다.
i
까지는, Stop
의 내용이 그대로 격납되고 있어, arr(1 To 6)
의 열거 완료시에는 col
가 col
가 되어 있기 때문에, 초기화되어 i
덧붙여서, 배열 변수의 형태 선언으로부터 7
를 빼고, Empty
라고 하면(자), ()
가 변수적인 것을 나타내는 보증이 없어지기 때문에, 컴파일 에러가 됩니다.
이것이 어떤 도움이 되는가?
변한 거동 때문에, 기본적으로는 도움이 되지 않는 것이라고는 생각합니다.
무리한 사용법을 생각하면, 「값과 오브젝트가 섞인 컬렉션을 Variant 배열에 격납한다」라고 하는 용도에서는, 일단 사용할 수 없지는 않습니다.
VBA에서는 변수적인 것에의 대입시에, 대입하는 것이 객체의 경우는 Dim arr As Variant
그 때문에, 대입하기 전에 어느 쪽인지 판정한 다음에 대입 방법을 전환할 필요가 있습니다.
참고 : VBA 개인 범용 처리 - Qiita
그러나 배열의 요소를 For Each의 변수로 지정하면 VBA 내부에서 대입을 해 주므로 판정 처리를 쓸 필요가 없어지고 (자신이 시도한 범위에서는) 처리 속도도 향상되었습니다.
Sub SpeedTest()
Const LoopCount = 1 * 10 ^ 7
Dim col As VBA.Collection
Set col = New VBA.Collection
Dim i As Long
For i = 1 To LoopCount
col.Add i
Next i
Dim tim As Single
Debug.Print "普通に配列へ代入",
tim = VBA.DateTime.Timer
Dim arr1() As Variant
ReDim arr1(1 To col.Count)
i = LBound(arr1)
Dim v As Variant
For Each v In col
'Object かそれ以外かで、代入方法を切り替える。
'この方法では問題になることがあるが、あまりない話なので省略。
'https://qiita.com/nukie_53/items/bde16afd9a6ca789949d#%E5%A4%89%E6%95%B0%E3%81%B8%E4%BB%A3%E5%85%A5
If VBA.Information.IsObject(v) Then
Set arr1(i) = v
Else
Let arr1(i) = v
End If
i = i + 1
Next v
Debug.Print VBA.Strings.Format$(VBA.DateTime.Timer - tim, "0.000")
Debug.Print "For Eachで配列に代入",
tim = VBA.DateTime.Timer
Dim arr2() As Variant
ReDim arr2(1 To col.Count)
i = LBound(arr1)
Dim limitIndex As Long
limitIndex = UBound(arr2)
For Each arr2(i) In col
'For Each が正常終了すると、最後の要素が Empty になってしまうことへの対策。
If i >= limitIndex Then Exit For
i = i + 1
Next arr2(i)
Debug.Print VBA.Strings.Format$(VBA.DateTime.Timer - tim, "0.000")
End Sub
기타
#VBA퀴즈 립으로 낮추고 있는 이미지의 코드를 실행했을 때, Stop 스테이트먼트의 위치에서, 배열 변수 b 의 내용은 어떻게 되어 있습니까? — 이미히토 (@nukie_53) 10월 14, 2020
Reference
이 문제에 관하여(VBA 수수께끼 사양 : For Each에서 지정하는 변수는 변수적이면 무엇이든 지정할 수 있으며 루프마다 평가됩니다.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/nukie_53/items/46391dc01c4d1b34b9d7
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
For Each element In group
statements
Next
ByRef が指定されたプロシージャの引数に指定したとき、プロシージャ内で変更された内容が反映される任意の式
Type SampleUDT
Value As Variant
End Type
Public varPublic As Variant
Sub VariableExpression()
Dim arr() As Variant
arr = VBA.[_HiddenModule].Array()
'任意の変数。
Dim varLocal As Variant
For Each varLocal In arr
Next varLocal
For Each varPublic In arr
Next varPublic
'配列の要素。
Dim varArr(0 To 0) As Variant
For Each varArr(0) In arr
Next varArr(0)
'ユーザー定義型のフィールド。
Dim varUdt As SampleUDT
For Each varUdt.Value In arr
Next varUdt.Value
'以下はNG
'For Each propValue In arr
'Next
End Sub
Public Property Get propValue() As Variant
End Property
Public Property Let propValue(inValue As Variant)
End Property
「배열의 요소」를 지정해
For Each
루프를 실시하는 샘플 코드입니다.Sub SampleForEach()
'VBA.Collection を新規インスタンスして、適当に中身を設定する。
Dim col As VBA.Collection
Set col = New VBA.Collection
'文字列・整数・小数・日付・オブジェクト・Null を設定。
col.Add "ABC"
col.Add 123
col.Add 3.14
col.Add VBA.DateTime.DateSerial(2021, 3, 27)
col.Add Err
col.Add Null
'Variant 型の配列を宣言し、VBA.Collection の要素数 + 1 だけ領域を確保する。
Dim arr() As Variant
ReDim arr(1 To col.Count() + 1)
'配列の末尾に「Hoge」を設定する。
arr(UBound(arr)) = "Hoge"
Dim i As Long
i = LBound(arr)
For Each arr(i) In col
i = i + 1
Next arr(i)
Stop
End Sub
이 코드에는
For Each arr(i) In col
라는 줄이 있으며 element
표시합니다.실제로
For Each
의 시점에서의 로컬 윈도우의 내용을 확인하면, 이하의 화상과 같이 되어 있습니다.i
까지는, Stop
의 내용이 그대로 격납되고 있어, arr(1 To 6)
의 열거 완료시에는 col
가 col
가 되어 있기 때문에, 초기화되어 i
덧붙여서, 배열 변수의 형태 선언으로부터
7
를 빼고, Empty
라고 하면(자), ()
가 변수적인 것을 나타내는 보증이 없어지기 때문에, 컴파일 에러가 됩니다.이것이 어떤 도움이 되는가?
변한 거동 때문에, 기본적으로는 도움이 되지 않는 것이라고는 생각합니다.
무리한 사용법을 생각하면, 「값과 오브젝트가 섞인 컬렉션을 Variant 배열에 격납한다」라고 하는 용도에서는, 일단 사용할 수 없지는 않습니다.
VBA에서는 변수적인 것에의 대입시에, 대입하는 것이 객체의 경우는 Dim arr As Variant
그 때문에, 대입하기 전에 어느 쪽인지 판정한 다음에 대입 방법을 전환할 필요가 있습니다.
참고 : VBA 개인 범용 처리 - Qiita
그러나 배열의 요소를 For Each의 변수로 지정하면 VBA 내부에서 대입을 해 주므로 판정 처리를 쓸 필요가 없어지고 (자신이 시도한 범위에서는) 처리 속도도 향상되었습니다.
Sub SpeedTest()
Const LoopCount = 1 * 10 ^ 7
Dim col As VBA.Collection
Set col = New VBA.Collection
Dim i As Long
For i = 1 To LoopCount
col.Add i
Next i
Dim tim As Single
Debug.Print "普通に配列へ代入",
tim = VBA.DateTime.Timer
Dim arr1() As Variant
ReDim arr1(1 To col.Count)
i = LBound(arr1)
Dim v As Variant
For Each v In col
'Object かそれ以外かで、代入方法を切り替える。
'この方法では問題になることがあるが、あまりない話なので省略。
'https://qiita.com/nukie_53/items/bde16afd9a6ca789949d#%E5%A4%89%E6%95%B0%E3%81%B8%E4%BB%A3%E5%85%A5
If VBA.Information.IsObject(v) Then
Set arr1(i) = v
Else
Let arr1(i) = v
End If
i = i + 1
Next v
Debug.Print VBA.Strings.Format$(VBA.DateTime.Timer - tim, "0.000")
Debug.Print "For Eachで配列に代入",
tim = VBA.DateTime.Timer
Dim arr2() As Variant
ReDim arr2(1 To col.Count)
i = LBound(arr1)
Dim limitIndex As Long
limitIndex = UBound(arr2)
For Each arr2(i) In col
'For Each が正常終了すると、最後の要素が Empty になってしまうことへの対策。
If i >= limitIndex Then Exit For
i = i + 1
Next arr2(i)
Debug.Print VBA.Strings.Format$(VBA.DateTime.Timer - tim, "0.000")
End Sub
기타
#VBA퀴즈 립으로 낮추고 있는 이미지의 코드를 실행했을 때, Stop 스테이트먼트의 위치에서, 배열 변수 b 의 내용은 어떻게 되어 있습니까? — 이미히토 (@nukie_53) 10월 14, 2020
Reference
이 문제에 관하여(VBA 수수께끼 사양 : For Each에서 지정하는 변수는 변수적이면 무엇이든 지정할 수 있으며 루프마다 평가됩니다.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/nukie_53/items/46391dc01c4d1b34b9d7
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
Sub SpeedTest()
Const LoopCount = 1 * 10 ^ 7
Dim col As VBA.Collection
Set col = New VBA.Collection
Dim i As Long
For i = 1 To LoopCount
col.Add i
Next i
Dim tim As Single
Debug.Print "普通に配列へ代入",
tim = VBA.DateTime.Timer
Dim arr1() As Variant
ReDim arr1(1 To col.Count)
i = LBound(arr1)
Dim v As Variant
For Each v In col
'Object かそれ以外かで、代入方法を切り替える。
'この方法では問題になることがあるが、あまりない話なので省略。
'https://qiita.com/nukie_53/items/bde16afd9a6ca789949d#%E5%A4%89%E6%95%B0%E3%81%B8%E4%BB%A3%E5%85%A5
If VBA.Information.IsObject(v) Then
Set arr1(i) = v
Else
Let arr1(i) = v
End If
i = i + 1
Next v
Debug.Print VBA.Strings.Format$(VBA.DateTime.Timer - tim, "0.000")
Debug.Print "For Eachで配列に代入",
tim = VBA.DateTime.Timer
Dim arr2() As Variant
ReDim arr2(1 To col.Count)
i = LBound(arr1)
Dim limitIndex As Long
limitIndex = UBound(arr2)
For Each arr2(i) In col
'For Each が正常終了すると、最後の要素が Empty になってしまうことへの対策。
If i >= limitIndex Then Exit For
i = i + 1
Next arr2(i)
Debug.Print VBA.Strings.Format$(VBA.DateTime.Timer - tim, "0.000")
End Sub
#VBA퀴즈 립으로 낮추고 있는 이미지의 코드를 실행했을 때, Stop 스테이트먼트의 위치에서, 배열 변수 b 의 내용은 어떻게 되어 있습니까? — 이미히토 (@nukie_53) 10월 14, 2020
Reference
이 문제에 관하여(VBA 수수께끼 사양 : For Each에서 지정하는 변수는 변수적이면 무엇이든 지정할 수 있으며 루프마다 평가됩니다.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/nukie_53/items/46391dc01c4d1b34b9d7텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)