VBA技術解説
VBAのVariant型について

ExcelマクロVBAの問題点と解決策、VBAの技術的解説
公開日:2020-06-30 最終更新日:2020-07-05

VBAのVariant型について


Variantデータ型は、他の何らかのデータ型として明示的に宣言されていない変数で、全てのデータ型を入れることができます。
Variantデータ型には型宣言文字はありません。


Variant型は、特別な値 Empty、Error、Nothing、Null を格納することもできます。
ただし、固定長文字列データ型として格納することはできません。
また、ユーザー定義型を格納することもできません。

Variantデータ型を他の具体的なデータ型の代わりに使用することにより、データをより柔軟に処理できます。
データ型の基本については以下を参照してください。
変数宣言のDimとデータ型|VBA入門
・データ型 ・変数の使い方 ・変数名の規則 ・良く使われる変数名 ・自動型変換、暗黙の型変換 ・変数宣言の必要性 ・Dim変数宣言のまとめ
定数宣言のConstと型宣言文字|VBA入門
・Const定数の基本 ・変数でも同じ事が出来るが・・・ ・ダブルクォーテーションについて ・型宣言文字 ・Constにデータ型を指定しない場合のデータ型 ・その他の定数 ・Const変数宣言のまとめ

目次

Variant型変数のデータ型を調べる

Variant型変数をローカルウィンドウでみると、Variant/の後に実際に入っているデータの型が表示されます。
・ローカル ウィンドウの表示 ・ローカル ウィンドウの基本的な使い方 ・ローカル ウィンドウの制限 ・ローカル ウィンドウの最後に

VBA マクロ Variant

Variant型変数のデータ型をVBAで判定する場合は、VarType関数またはTypeName関数を使用します。

VarType関数は、引数に指定された変数の内部処理形式を表す整数型(Integer)の値を返します。
VarType関数は、引数に指定された変数の内部処理形式を表す整数型(Integer)の値を返します。VarType関数 VarType(varname) varname 必ず指定します。引数varnameには、ユーザー定義型の変数を除く、任意のバリアント型(Variant)の変数を指定します。
TypeName関数は、引数で指定された変数に関する情報を文字列で返します。
TypeName関数は、引数で指定された変数に関する情報を文字列で返します。TypeName関数 TypeName(varname) varname 必ず指定します。ユーザー定義型の変数を除く、任意のバリアント型(Variant)の変数を指定します。

バリアント型 (Variant) 変数の初期値はEmptyです。
変数がEmpty値であるかの判定には、IsEmpty関数を使用してください。
・IsEmpty関数 ・IsEmpty関数の使用例 ・Is○○関数一覧

Variant型変数のメモリアドレス

変数のアドレス位置にはデータ型を区別する数値が入っています。
詳しくは以下を参照してください。
VBAにおける変数のメモリアドレスについて
・メモリアドレスを取得する関数とメモリコピーのWindowsAPI ・メモリアドレスを確認するために使用したVBA ・文字列型Stringのメモリアドレス ・Integer, Long, Single, Double, Dateのメモリアドレス ・Variantのメモリアドレス ・配列のメモリアドレス ・オブジェクトのメモリアドレス ・ByRef,ByValのメモリアドレス

Variant型どうしの算術演算

Byte、Integer、Long、Singleを格納しているVariant対して算術演算を実行し、結果が元のデータ型の通常の範囲を超えた場合、結果は Variant内で次に大きいデータ型に昇格されます。
ByteはIntegerへ、IntegerはLongへ、LongとSingleはDoubleへ昇格されます。

Dim v1, v2, v3, v4, v5, v6, v7
v1 = CByte(125)
v2 = CByte(125)
v3 = v1 + v2
v4 = v1 * v2
v5 = v1 * v2 * 10
v6 = v1 ^ v2
v7 = v1 / v2
Stop
VBA マクロ Variant

Currency、Decimal、Doubleの値が格納されているVariant変数がそれぞれの範囲を超えると、エラーが発生します。

Variant型どうしの比較演算

バリアントの基になる型に応じて、式の比較方法または比較の結果が変わります。

条件 Then
両方のバリアント型 (Variant) の式が数値 数値比較を実行します。
両方のバリアント型 (Variant) の式が文字列 文字列比較を実行します。
一方のバリアント型 (Variant) の式が数値で、もう一方が文字列 数値式は文字列式よりも小さくなります。
一方のバリアント型 (Variant) の式がEmptyで、もう一方は数値 0をEmpty式として使用して、数値比較を実行します。
一方のバリアント型 (Variant) の式がEmptyで、もう一方が文字列 長さ0の文字列 ("") をEmpty式として使用して、文字列比較を実行します。
両方のバリアント型 (Variant) の式がEmpty 式は等しくなります。

最も注意すべき点は、一方が数値で、もう一方が文字列の場合です。
数値式は文字列式よりも小さくなります。

Dim v1, v2
v1 = 123
v2 = "120"
Debug.Print v1 < v2
Debug.Print v1 = v2
Debug.Print v1 > v2

上記VBAにおいては、実際の数値に関係なく常に、
True ・・・ 左辺が数値式なのでTrueになります。
False
False
このように数値式は常に小さく判定されます。

RangeのValueプロパティの比較

RangeのValueプロパティはVariantです。
従ってVariantの比較になるので注意が必要です。

VBA マクロ Variant
A1は数値、A2は文字列になっています。

VBA マクロ Variant

Dim v
v = "123"
Debug.Print Range("A1").Value = Range("A2").Value
Debug.Print Range("A1").Value = v
Debug.Print Range("A2").Value = v

数値式は文字列式よりも小さくなりますので、この結果は、
False
False
True ・・・ 文字列式どうしの比較
となります。

つまり、Valueは単純比較できません。
文字列を数値変換するには、
CLng関数
・CLng関数 ・CLng関数の使用例 ・について ・データ型変換関数一覧
CDbl関数
・CDbl関数 ・CDbl関数の使用例 ・倍精度浮動小数点数型 (Double)について ・データ型変換関数一覧
これらを使いますが、そもそも数値に変換できない場合はこれらの関数がエラーとなってしまいます。
そこで、事前に数値変換可能かを、IsNumeric関数を使い判定しておきます。
・IsNumeric関数 ・IsNumeric関数の使用例 ・Is○○関数一覧
さらに、そもそもエラー値の判定は、IsError関数で行う必要があります。
・IsError関数の構文 ・IsError関数の使用例 ・Is○○関数一覧

Sub test()
  Debug.Print CompareValue(Range("A1"), Range("A2"))
End Sub

Function CompareValue(rng1 As Range, rng2 As Range)
  'エラー値の場合はFalseを返す
  If IsError(rng1.Value) Or IsError(rng2.Value) Then
    CompareValue = False
    Exit Function
  End If
  
  '両方数値の場合は数値比較する
  If IsNumeric(rng1.Value) And IsNumeric(rng2.Value) Then
    If CDbl(rng1.Value) = CDbl(rng2.Value) Then
      CompareValue = True
    Else
      CompareValue = False
    End If
    Exit Function
  End If
  
  '文字列比較
  If rng1.Value = rng2.Value Then
    CompareValue = True
  Else
    CompareValue = False
  End If
End Function

ユーザー定義型(Type)とバリアント(Variant)変数

ユーザー定義型をバリアント(Variant)変数に代入するとエラーとなります。

VBA マクロ Variant

VBAリファレンスには、
(Variant 型はユーザー定義型をサポートするようになりました)。
このように書かれていますが、
これは、ActiveXプロジェクトやタイプライブラリの構造体の事をさしていると思われます。
VBA内で定義した構造体を、バリアント(Variant)変数に代入することはできません。

Variant型の配列

通常の配列には、同じデータ型しか入れることはできません。

Dim n(1 To 3) As Long

この変数nの各要素には、数値または数値変換可能な文字しか代入できません。
しかし、Variant型の場合は、任意のデータ型を入れることができます。

Dim n(1 To 3) As Variant
n(1) = 123
n(2) = 1.23
n(3) = "ABC"
Stop

VBA マクロ Variant

配列をVariant型の仮引数に渡す

配列を引数に指定する場合は、ByRef(参照渡し)が強制されます。
ByValで配列を指定した場合は、赤字のコンパイルエラーとなります。

VBA マクロ Variant

しかし、仮引数をVariantで直接受け取る場合はByValで受け取ることができます。

Sub test()
  Dim str(2) As String
  str(0) = "A": str(1) = "B": str(2) = "C"
  Dim v
  v = fnc(str)
  Stop
End Sub

Function fnc(ByVal v) As Variant
  v(0) = "Z"
  fnc = v
End Function

VBA マクロ Variant

RangeオブジェクトをVariant型の仮引数に渡す

RangeオブジェクトをVariantの仮引数に渡した場合の挙動については注意が必要です。

ByRef、ByVal、どちらで受け取っても受け取った時点ではRangeオブジェクトです。
しかし、仮引数に何かを代入した時点で違いが出てきます。

ByVal、ByRefの基本については以下を参照してください。
値渡し(ByVal)、参照渡し(ByRef)について
・ByVal(値渡し)とByRef(参照渡し) ・普通の変数(プリミティブ型)の場合 ・オブジェクト変数の場合 ・サイト内のByVal,ByRefの記事

Sub sample()
  Dim rng1 As Range
  Dim rng2 As Range
  Set rng1 = Range("A1:B1")
  Set rng2 = Range("A2:B2")
  Call sample_sub(rng1, rng2)
End Sub

Sub sample_sub(ByRef v1, ByVal v2)
  Stop '①
  v1 = 1
  v2 = 1
  Stop '②
End Sub

①の時点:受け取った直後

v1、v2、どちらもRangeオブジェクトとして受け取ります。

VBA マクロ Variant

②の時点:代入した後

ByRefで受け取ったv1は、Let代入ではValueに入ります。
ByValで受け取ったv2は、Let代入では変数が置き換わります。

VBA マクロ Variant

ただし、当然ではありますが、
Set代入した場合は、代入したオブジェクトになります。

Valueの配列で渡したい場合

呼び出す時に配列で渡すようにします。
Call sample_sub(rng1, rng2)
これを
Call sample_sub(rng1.Value, rng2.Value)
このように、Valueプロパティを指定すればValueの配列で渡せます。
また、
Call sample_sub((rng1), (rng2))
このように、()での値評価をすれば、その時点で既定プロパティのValueが取得されるので、Valueの配列で渡せます。
ただし、実引数にCVar(…)としても配列になりません。



同じテーマ「マクロVBA技術解説」の記事

VBAの小数以下の演算誤差について
スピルでVBAの何が変わったか
CharactersプロパティとCharactersオブジェクト
ユーザーに絶対に停止させたくない場合のVBA設定
印刷範囲の設定・印刷範囲のクリア
VBAの省略可能な記述について
VBAのVariant型について
VBAのインデントについて
VBAの演算子まとめ(演算子の優先順位)
列幅不足による###表示や指数表示を判定する
VBA10大躓きポイント(初心者が躓きやすいポイント)


新着記事NEW ・・・新着記事一覧を見る

ブール型(Boolean)のis変数・フラグについて|VBA技術解説(2024-04-05)
テキストの内容によって図形を削除する|VBA技術解説(2024-04-02)
ExcelマクロVBA入門目次|エクセルの神髄(2024-03-20)
VBA10大躓きポイント(初心者が躓きやすいポイント)|VBA技術解説(2024-03-05)
テンキーのスクリーンキーボード作成|ユーザーフォーム入門(2024-02-26)
無効な前方参照か、コンパイルされていない種類への参照です。|エクセル雑感(2024-02-17)
初級脱出10問パック|VBA練習問題(2024-01-24)
累計を求める数式あれこれ|エクセル関数応用(2024-01-22)
複数の文字列を検索して置換するSUBSTITUTE|エクセル入門(2024-01-03)
いくつかの数式の計算中にリソース不足になりました。|エクセル雑感(2023-12-28)


アクセスランキング ・・・ ランキング一覧を見る

1.最終行の取得(End,Rows.Count)|VBA入門
2.セルのコピー&値の貼り付け(PasteSpecial)|VBA入門
3.RangeとCellsの使い方|VBA入門
4.ひらがな⇔カタカナの変換|エクセル基本操作
5.繰り返し処理(For Next)|VBA入門
6.変数宣言のDimとデータ型|VBA入門
7.ブックを閉じる・保存(Close,Save,SaveAs)|VBA入門
8.並べ替え(Sort)|VBA入門
9.セルのクリア(Clear,ClearContents)|VBA入門
10.Findメソッド(Find,FindNext,FindPrevious)|VBA入門




このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。


記述には細心の注意をしたつもりですが、
間違いやご指摘がありましたら、「お問い合わせ」からお知らせいただけると幸いです。
掲載のVBAコードは動作を保証するものではなく、あくまでVBA学習のサンプルとして掲載しています。
掲載のVBAコードは自己責任でご使用ください。万一データ破損等の損害が発生しても責任は負いません。


このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。
本文下部へ