7
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

VBAでもTupleが使いたい

Last updated at Posted at 2018-07-06

はじめに

VBAではFunctionで複数の値を返したい時にC#みたいにTupleが使えない

例えばこんな感じのFunctionがあるとする
(こんなのFunctionにする必要ないのでは?というツッコミはなしで)

Function TryToInt(value As Variant) As Integer
    If IsNumeric(value) Then
        TryToInt = CInt(value)
    Else
        TryToInt = 0
    End If
End Function

これは引数で受け取ったvalueがIntegerに変換できれば変換した値を、できなければ0を返している
しかし、これだと変換に失敗したかを0で判定するというルールを使う側に強いることになる
また、valueに0を渡した時には変換に失敗した扱いになるという致命的な問題がある

Sub Hoge()
    Dim fuga As String: fuga = "23"
    Dim piyo As Integer
    
    piyo = TryToInt(fuga )
    
    If piyo <> 0 Then
        Debug.Print piyo
    Else
        Debug.Print "あばばばば"
    End If
End Sub

それならと、戻り値をVariantにして失敗時にNullを返すとする

Function TryToInt(value As Variant) As Variant
    If IsNumeric(value) Then
        TryToInt = CInt(value)
    Else
        TryToInt = Null
    End If
End Function
Sub Hoge()
    Dim fuga As String: fuga = "23"
    Dim piyo As Variant
    
    piyo = TryToInt(fuga )
    
    If Not IsNull(piyo) Then
        Debug.Print CInt(piyo)
    Else
        Debug.Print "あばばばば"
    End If
End Sub

こうすると0を渡した時の問題は解決するが、変換に成功したかの判定にはNullチェックを強要される
また、Variantで帰ってくるので厳密に型を要する場合は結局キャストする必要がある

調べてみたら、この他にも戻り値を配列にしたり、参照渡しでなんとかしたり...などなどいろいろなやり方があったけど、しっくりくるものは見つからなかった

Typeを使おう

ということでどうにかしてC#のTupleみたいな感じのことをしようと考えた時、Typeを使う方法を思いついた
Typeとは、ユーザー定義型といい、いわゆる構造体のこと
このTypeに変換した値と成功したかどうかを入れて返せばTupleっぽいことができそう
注)プロシージャより上に定義する必要があり、PublicなTypeは標準モジュールにのみ定義可能

Type IntBoolTuple
    Value As Integer
    IsSucceeded As Boolean
End Type

こうやってTypeを定義して

Function TryToInt(Value As Variant) As IntBoolTuple
    Dim res As IntBoolTuple
    If IsNumeric(Value) Then
        res.Value = CInt(Value)
        res.IsSucceeded = True
    Else
        res.IsSucceeded = False
    End If
    TryToInt = res
End Function
Sub Hoge()
    Dim fuga As String: fuga = "23"
    Dim piyo As IntBoolTuple

    piyo = TryToInt(fuga )
    
    If piyo.IsSucceeded Then
        Debug.Print CInt(piyo.Value)
    Else
        Debug.Print "あばばばば"
    End If
End Sub

こうやって使う
こうすれば前述した問題を解決でき、可読性が上がり、インテリセンスまで効くようになる

問題点

ただ、これも少し問題点がある

違う複数の値を返したい時に新たにいちいちTypeを定義する必要がある
今回の例のように、IntegerとBooleanではなくStringとBooleanを返したい時などはまたTypeを定義する必要があってめんどくさい
また、型を決めてしまっていると汎用性がなくなる
これは型をVariantにすればある程度は解消できる

Type Tuple
    Value As Variant
    IsSucceeded As Boolean
End Type

ただし、厳密に型を扱う時にはキャストする必要があるし、返したい値の数が変わった時(Valueに加えてValue2も返したい時とか)は新たにTypeを定義する必要がある

おわりに

複数の値を返すのが少しマシになったかと思う
必ずしもこのやり方がいいとは限らないので、ケースバイケースで使い分けてね
ほかにいいやり方があれば教えて下さい(人∀・)

まぁどんなに工夫してもなにかしらの不満は残るだろうから、そもそもVBAを使わないのが一番の解決策だと思う( ˘ω˘)

7
5
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?