2010年11月16日火曜日

Dictionary のキーはデータ型を区別するか

ふつう Dictionary のキーには、文字列なら文字列、数値なら数値と、同じデータ型を使います。というか、キーにデータ型が混在するという状況自体が想像つきませんけれど。
しかし、仮にそういう状況があったとしたら、何が起きるのでしょうか。
ほとんど実際の役には立たないと思いますが、興味本位で試してみました。

まず数値の区別。

Sub Test1()
    Dim d As New Scripting.Dictionary

    d("0") = 1  ' 数字 (文字列)
    d(0) = 2    ' 数値 (Integer)
    d(0#) = 3   ' 数値 (Double)

    Debug.Print d("0"), d(0), d(0#)
    '  1         3             3
End Sub

上記で分かるように、数値同士であれば型の違いは無視されるようです。
内部的には Real か何かに変換されているのでしょうか。
文字列の数字とはしっかり区別してくれます。これはもちろん、そうあるべきです。

続いて、日付/時刻型とシリアル値を比較してみます。これはちょっと微妙な予感…。

Sub Test2()
    Dim d As New Scripting.Dictionary

    d(#11/15/2010#) = 1             ' 日付/時刻型
    d(40497) = 2                    ' 数値 (上記と同じシリアル値)
    d(#11/15/2010 12:00:00 PM#) = 3 ' 日付/時刻型
    d(40497.5) = 4                  ' 数値  (上記と同じシリアル値)
    d(#11/15/2010 4:35:12 AM#) = 5  ' 日付/時刻型
    d(40497.1911111111) = 6         ' 数値 (上記と同じシリアル値)

    Debug.Print d(#11/15/2010#), d(40497), _
                d(#11/15/2010 12:00:00 PM#), d(40497.5), _
                d(#11/15/2010 4:35:12 AM#), d(40497.1911111111)
    '  2         2         4         4         5         6
End Sub

ご覧の通り、日付/時刻型とシリアル値は基本的に区別されません。
時刻部が微妙な端数だと区別されていますが、これはおそらく浮動小数点誤差によるものではないでしょうか。データ型を区別しているようには見えません。

原理を考えると、Dictionary の内部はハッシュ テーブルでしょうから、キーの型が何であれ最終的にハッシュ衝突を起こせば同値とみなされるのは当然と言えます。もしハッシュ値を求める際にデータ型の情報を含めていれば、型による区別は可能ですが、実際問題そんな実装 誰から期待されているのかとか、0 と 0& と 0# を別物として取り扱われると逆に困らないか、などと考えると、妥当な実装ではないでしょうか。

正直、これを知っていると得する場面とか、逆に知らないと困る場面とかは想像するのが困難ですが、強いて言うなら、飲み会等でトリビア自慢が始まったときに一瞬で周囲を黙らせたい (または二度と振られたくない) 場面で思い出すとよいかもしれません。

0 件のコメント:

コメントを投稿