今年の夏にGo言語に以下のようなプロポーザルを出していたのですが、それが先ほど承認されました。標準パッケージの関数追加になります。 proposal: bytes, strings: add ContainsFunc · Issue #54386 · golang/go · GitHub
Go言語のstringsパッケージとbytesパッケージには、文字列から文字や部分文字列を探す関数がいくつかあります。 探す文字の位置を返す関数、最後から探す関数、そういう文字が含まれるかどうかを返す関数を表にまとめると、次のようになります。
Find what? | Index* | LastIndex* | Contains* |
---|---|---|---|
substr string |
Index(s, substr string) int |
LastIndex(s, substr string) int |
Contains(s, substr string) bool |
chars string |
IndexAny(s, chars string) int |
LastIndexAny(s, chars string) int |
ContainsAny(s, chars string) bool |
c byte |
IndexByte(s string, c byte) int |
LastIndexByte(s string, c byte) int |
-- |
r rune |
IndexRune(s string, r rune) int |
-- | ContainsRune(s string, r rune) bool |
f func(rune) bool |
IndexFunc(s string, f func(rune) bool) int |
LastIndexFunc(s string, f func(rune) bool) int |
Proposal #54386 |
私がプロポーザルで出したのは、関数で指定した条件に当てはまる文字が含まれるかどうかというContainsFunc
関数です。
文字列の中から関数で条件を指定して当てはまる文字を探すためには、IndexFunc
の返り値から判定しなくてはいけませんでした。
hasControlRune := strings.IndexFunc(target, unicode.IsControl) >= 0
これで良いという話ではありますが、いつもいつも数字と比較するのは面倒ですし、読みやすくもありません。
それに >= 0
か != -1
かといった書き方の好みも分かれてしまい、どちらが良いかというナンセンスな議論を生んでしまいます。
strings.ContainsFunc
があれば、コードの意図がより分かりやすくなるのではないでしょうか。
hasControlRune := strings.ContainsFunc(target, unicode.IsControl)
最初はgojqを書いている時に、上のような判定コードでstrings.ContainsFunc
が欲しくなったというのがきっかけでした。
この関数があるとどれくらい嬉しいかということを主張するために、semgrepでGo言語のリポジトリをスキャンしてみたのですが、strings.IndexFunc
やbytes.IndexFunc
を使っている9箇所のうち、6箇所がContainsFunc
で置き換えられることが分かりました。
過半数が文字が含まれているかの判定で使われていて、位置自体を欲しいケースは半分以下ということですね。
これはContainsFunc
追加をサポートする良い材料だと思い、プロポーザルに書いてみました(本来はもっと大きなコードベースで調査した方がいいのでしょう)。
まずslices.ContainsFunc
という別のプロポーザルが承認され、これと関連している私のプロポーザルも先ほど承認されました。
Go言語にプロポーザルを出したのは初めてでしたが、特に白熱した議論が繰り広げられることもなく、すんなり承認されましたね。
自分の提案がきっかけで実装される機能が世に出るのは楽しみです。
\広告です/