しばたテックブログ

気分で書いている技術ブログです。

PowerShell 6.0で範囲演算子(..演算子)が拡張される話

とあるPull RequestがきっかけでPowerShell 6.0 RC1から範囲演算子(..演算子)が拡張され、Int型だけでなくChar型も扱える様になりました。

本エントリではその内容について説明します。

範囲演算子でChar型が扱える様になります

もともと範囲演算子(..)は、

1..5

の様に[Int型の数値]..[Int型の数値]の形式をとり、指定した数値間で連続する要素を持つ配列を生成します。

# 1~5を要素にもつ配列が生成される
1..5 => (1,2,3,4,5)

f:id:stknohg:20171221213103p:plain

今回、この指定がChar型を取れる様に拡張され、以下の様な記述が可能になります。

'a'..'e'

この例の場合だとaeを要素にもつ配列が生成されます。

# a~eを要素にもつ配列が生成される
'a'..'e' => ([char]'a', [char]'b', [char]'c', [char]'d', [char]'e')

f:id:stknohg:20171221213133p:plain

ただ、PowerShellにはChar型リテラルを表現する手段はないため、'a''e'の記述は実際にはString型であり内部的にChar型へのキャストが発生しています。

# 内部的にはString型→Char型へのキャストが発生しているイメージ
[char]'a'..[char]'e'

もう少し深入りしてみる

これだけだとなんとなくそんなものかという感じですが、この機能拡張はまだバギーなうえかなり気持ち悪い挙動をします。

PowerShellにおけるChar型と本機能拡張

元のPull Requestを見てわかる様に、この機能拡張はもともと、

'a'..'z'

の様な単純なASCIIの範囲の文字の使用を想定している様です。

ただ、PowerShellは.NET Framework/.NET Core製であり.NETの世界のChar型はUnicode Characterです。

このため、

'あ'..'お'

の様な指定も可能となり、以下の様な結果を返します。

f:id:stknohg:20171221213229p:plain

これはざっくり以下と同義になります。

[int][char]'あ'..[int][char]'お' | % { [char]$_ }

現時点で発生しているバグ

現時点で以下のバグが報告されており、

github.com

'あ'..'お' | % { [int]$_ }

の様な記述がエラーとなってしまいます。

f:id:stknohg:20171221213254p:plain

いまのところ()でくくることで回避可能ですが早急に修正してほしい感じです。

# ()でくくることでバグを回避できる
('あ'..'お') | % { [int]$_ }

また、私も別件で以下のIssueを報告しています。

github.com

現状の出来を見るに、個人的には機能を拡張するには軽率だったんじゃないかと思いますし、今からでもこの拡張は取り下げた方が良いんじゃないかとさえ思えます...

型変換の仕様との演算子の整合性について

個人的な感情はとりあえず置いておいて、今回の拡張によって範囲演算子はInt型およびChar型を受け入れることができる様になりました。

ではInt型とChar型を混在させたときはどうなるかというと次の様になります。

  • [Char型] .. [Int型]の場合はOK
# OK
'a'..100

f:id:stknohg:20171221213537p:plain

  • [Int型] .. [Char型]の場合はNG
# NG
95..'a'

f:id:stknohg:20171221213552p:plain

これはPowerShellの二項演算子が左オペランドの型に合わせようとする原則があるためです。
比較演算子のケースですが過去のこちらのエントリが参考になるでしょう。

blog.shibata.tech

PowerShellではInt型からChar型へのキャストは直接行えるのですが、

# OK
[char]100

Char型からInt型へのキャストについては、記述上String型からInt型へのキャストが必要になり、PowerShellにはString型を直接Intにキャストできないため構文エラーとなります。

# NG : String型 → Int型へ直接キャストはできない
[int]'a'

# OK : Char型からInt型へのキャストなら可
[int][char]'a'

なお、Char型からInt型へのキャストは可能なので、

# OK : String型 → Char型 → Int型へのキャストとなる
95..[char]'a'

の様に記述すれば[Int型] .. [Char型]の場合でもエラーなく実行することができます。

f:id:stknohg:20171221213804p:plain

【2017/12/22】 ちょっと追記

String型からInt型へのキャストについて、

[int]'1'

の様に文字列で数値を表現している場合は可能です。
このため、

# これはPowerShell 6.0以前でも可能
'1'..'5'

# これもPowerShell 6.0以前で可能
95..'97'

の様な記述であればエラーなく可能です。

最後に

とりあえずこんな感じです。

この範囲演算子の拡張は個人的には不要とさえ思っているのですが何かしら役に立つケースもあるかもしれません。