2012年6月20日水曜日

◆単数と複数を同一に扱う(V3)

New V3 Language Features - Windows PowerShell Blog - Site Home - MSDN Blogsで説明されていたV3の機能をちょっと試してみました。

まずはちょっと便利になった単数と複数を同一視してくれる機能。

PS>dir


    ディレクトリ: C:\Users\minminnana\test


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        2012/06/20     11:18         10 a.txt

上記のようなディレクトリで以下のようなコマンドを実行すると、

PS>(dir).fullname
C:\Users\minminnana\test\a.txt

となります。

しかし、これがうまくいくのはどちらかというと「たまたま」で、誰かがここにファイルを追加したりすると突然機能しなくなります。

PS>"aaa" > b.txt
PS>dir


    ディレクトリ: C:\Users\minminnana\test


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        2012/06/20     11:18         10 a.txt
-a---        2012/06/20     11:33         12 b.txt


PS>(dir).fullname
PS>

これは、(dir)で返ってくるオブジェクトが単数の場合はファイルオブジェクト、複数の場合はオブジェクト配列になることが原因です。

PS>dir


    ディレクトリ: C:\Users\minminnana\test


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        2012/06/20     11:18         10 a.txt


PS>(dir).gettype()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     FileInfo                                 System.IO.FileSystemInfo


PS>"aaa" > b.txt
PS>(dir).gettype()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

この単数と複数の挙動の違いは誰しもが一度は嵌る道のように思います。

これまでは、この単数と複数の挙動の違いを吸収するために@()などで変数を定義して単数でも配列扱いとする方法が使われましたが、V3ではPowerShell側がこの違いを良きに計らってくれるようです。

V3ではこんな感じになります。

PS>dir


    ディレクトリ: C:\Users\minminnana\test


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        2012/06/20     11:45         12 a.txt
-a---        2012/06/20     11:45         12 b.txt


PS>(dir).fullname
C:\Users\minminnana\test\a.txt
C:\Users\minminnana\test\b.txt

これまでは、複数オブジェクトの場合は自分でループして個々のプロパティを参照する必要がありました。

PS>dir | %{$_.fullname}
C:\Users\minminnana\test\a.txt
C:\Users\minminnana\test\b.txt
PS>dir | % fullname
C:\Users\minminnana\test\a.txt
C:\Users\minminnana\test\b.txt

(最初の例はこれまでのV2の書き方、2つ目はV3での書き方。)

パイプを使った書き方も簡略化されているので、

> (dir).fullname
> dir | % fullname

どちらもタイプ量的には似たようなものですが、Blogによると前者のほうが(内部的にパイプ処理に展開しているわけではないので)高速だと書いてあるように読めました。

他にもCountプロパティが参照できたり添え字付きで参照できたりといった感じになっているようです。

V2

PS>$a = 1
PS>$a.count
PS>$a[0]
型 System.Int32 のオブジェクトにインデックスを付けることはできません。
発生場所 行:1 文字:4
+ $a[ <<<< 0]
    + CategoryInfo          : InvalidOperation: (0:Int32) []、RuntimeException
    + FullyQualifiedErrorId : CannotIndex

V3

PS>$a = 1
PS>$a.count
1
PS>$a[0]
1


また、もともとオブジェクト配列に持っているプロパティの場合はそちらが優先されるようです。

PS>$a = "aaa","b","cc","ddd"
PS>$a.length
4
PS>$a | % length
3
1
2
3

0 件のコメント:

コメントを投稿