2008年7月12日
VBScriptにおけるpushの決定版
VBScriptの配列は扱いづらいことで有名(?)ですが、pushを定義したらだいぶましになりました。以前から使っていたのだけど、改良を重ねてこれが決定版。
Sub push(arr,elm)
Dim i,tmp : i = 0
If IsArray(arr) Then
For Each tmp In arr
i = 1
Exit For
Next
If i=1 Then
Redim Preserve arr(Ubound(arr)+1)
Else
Redim arr(0)
End If
Else
arr = Array(0)
End If
If IsObject(elm) Then
Set arr(Ubound(arr)) = elm
Else
arr(Ubound(arr)) = elm
End If
End Sub
実行コードサンプル
Dim hoge()
push hoge,"test"
push hoge,Array(1,2,"fuga",44)
Dim fuga : Set fuga = CreateObject("Scripting.Dictionary")
fuga("item1") = "testitem"
push hoge,fuga
WScript.Echo(hoge(0))
WScript.Echo(hoge(1)(3))
WScript.Echo(hoge(2)("item1"))
これで、配列にオブジェクトやら配列やらを突っ込めてフリーダムな感じ。ひゃっほー。配列にはオブジェクト格納できないのかと思ってたら、「Set」を使えばできるんだね。実はVBScriptでもかなり複雑なデータ構造が実現可能。Classも定義できるし。ちなみに、こうやって配列にオブジェクトを突っ込むと参照渡しになるようだ。配列だと値渡し。
配列関係の条件分岐が複雑になっているが、空の配列の定義方法によって挙動が異なるのが理由。
Dim hoge : hoge = Array()
→IsArray()はTrue。UBound()を使うと、-1が返るDim hoge()
→IsArray()はTrue。UBound()を使うと、即エラー(!)Dim hoge(-1)
→こういう宣言は不可能(即エラー)
2の変数宣言の方法がシンプルで好きなのだが、こうすると型が形だけ配列扱いになるだけで、Uboundで配列の長さも取得できないというクソ仕様。なんで、コレクションを見に行って、ひとつでも要素があれば配列を伸ばすという形にした。
かなり無理やりなので、メモリはすげー無駄遣いしてるんだろうなぁ。Perlみたいに、無名ハッシュみたいなのを直接入れたり、深いデータ構造の自動生成とかは流石にさせられないのが残念。
それと、配列を走査して書き出したりしようと、オブジェクトを書き出そうとしたときにエラー吐いちゃうんだよね。オブジェクトにtoStringみたいなのを定義できない(多分)のが困る。