昨日のコードちょっと修正
昨日書いたコード、ちょっと修正してみた。元の記事の「いかがだろう、ずいぶんとすっきり記述できる。」という所に少しでも近づきたいという気持ちがあって、いや、あのIfブロックはあれはあれで、ハッキリとした意思表示だと思うんだけど、もっとスパっとかけないもんかなーと。
で、Queueなら! と思いついて利用箇所をこう変えた。
'こんな風に書けるよ! Dim hogeParam1 As String = "hogedefault1" 'set default Dim hogeParam2 As String = "hogedefault2" 'set default If opts.ContainsKey("hoge") Then With opts("hoge") hogeParam1 = If(.Count > 0, .Dequeue, "hogedefault1") hogeParam2 = If(.Count > 0, .Dequeue, "hogedefault2") End With End If
見た目はだいぶマシになった。先方のサンプルにあるportとrootを取る記述にしてみる。
Dim myOptions() As String = {"root", "port"} Dim opts = (New OptionParser(myOptions, "-"c)).Parse(args) 'こんな風に書けるよ! Dim root As String If opts.ContainsKey("root") Then root = If(opts("root").Count > 0, opts("root").Dequeue, ".") End If Dim port As Integer If opts.ContainsKey("port") Then If Not Integer.TryParse(If(opts("port").Count > 0, opts("port").Dequeue, "80"), port) Then port = 80 End If End If
実際の利用場面を想定したコードだと、それほどのスッキリ感はないなあ。でも、If式でデフォルト値とセットで書けるのはだいぶコンパクトにまとめられるようになったと思う。横に長くなるけども。
あと整数値を取るときの型変換がダルイなー。一気にみてくれがわるくなった。でもまあ、こんなもんじゃないかな。過剰に美しさを求めると、他が犠牲になったりするし、ここでやめとこう。
そうそう、パーサクラスはこうなった。
Public Class OptionParser Private listOfOptionName As New List(Of String) Private swChar As Char Public Sub New(ByVal args() As String, ByVal swc As Char) swChar = swc listOfOptionName = args.Distinct().ToList() End Sub Public Function Parse(ByVal args() As String) As Dictionary(Of String, Queue(Of String)) Parse = New Dictionary(Of String, Queue(Of String)) For i = 0 To args.Length - 1 Dim targetArg = args(i) If listOfOptionName.Exists(Function(n) String.Format("{0}{1}", swChar, n) = targetArg) Then Parse.Add(targetArg.Remove(0, 1), New Queue(Of String)) Else If Parse.Count > 0 AndAlso targetArg(0) <> swChar Then Parse.Last.Value.Enqueue(targetArg) Else Debug.Print("{0} droped.index={1}", targetArg, i) End If End If Next End Function End Class
DictionaryのValueがQueueになっただけ。ああ、あとSubstringをRemoveに変更。こんな便利関数があるなんて、今でもVB6現役のボクは知りませんでした!