Rustには様々な便利メソッドがある。最近知ったのはこのふたつだが、こういうかゆいところに手が届く機能が標準でCやC++にはない。C#にもPythonにもない。
- i32::abs_diff
- ふたつのi32値の絶対値の差
- Option::and_then
- Someなら関数を適用して、Noneならそのまま
abs_diff() は距離や適合度のスコアの算出に有用だ。用途が特殊ながらも、使うときには使うので、ちょっとしたショートカットにしかならないが、あると嬉しい。
and_then() の出番はもうちょっと多い。null値であればnullのままで、そうでなければ関数を適用したいという状況はよくある。nullableな値からオブジェクトを作るときやnullableオブジェクトから値を取り出すときがそうだ。
例えばC#ではこういうコードを書く。Cスタイルの三項演算子が見慣れた人にとってはあまり違和感はないが、行数が増えるし、なんといっても「nullであればnullを返す」というところに冗長さを感じなくもない。
var modifiedAt = modifiedAtInSeconds is not null
? DateTimeOffset.FromUnixTimeSeconds(modifiedAtInSeconds)
: null;Pythonではこうなる。よく取り沙汰されるPythonのインラインif-elseだが、Pythonを好んで書く私も実は好きではない。英文としても読めるし、コンセプトは悪くないのだが、構文的な美しさの観点では劣る。
書き方は違うもののC#と同じ問題は抱えたままだ。Pythonではオフサイドルールを採用していることもあり、可読性のために \ が必要になってしまうことも多い。
modified_at = None if modified_at_seconds is None \
else datetime.fromtimestamp(modified_at_seconds)これを解決するものが and_then() だ。実装は難しくないので割愛するが、これひとつあればC#でもPythonでもスッキリ書ける。C#はExtensionで実装できると思うが検証はしていない。
var modifiedAt = modifiedAtInSeconds.AndThen(x => DateTimeOffset.FromUnixTimeSeconds(x));modified_at = and_then(modified_at_seconds, lambda x: datetime.fromtimestamp(x))これまでユーティリティ的な関数の定義や拡張を追加することは嫌っていたが、可読性のためにはこのような工夫も積極的に行なっていくべきではないか?とも最近思うのである。