また serde-rs/json にPR投げてmergeされたので Value::pointer / Iterator::try_fold のおすすめメソッド2選についてメモ

また?

前回のです serde-rs/json にPR投げてmergeされた - KRAZY感情STYLE

今回のPR

github.com

Value::pointer とは

pointer を使わずに obj[x][y] を取ってくる例を考えてみます

use serde_json::{Value, json};

let obj = json!({"x": {"y": 1}});
let value = if let Value::Object(obj) = obj {
    let x = obj.get("x");
    if let Some(Value::Object(child_obj)) = x {
        child_obj.get("y")
    } else {
        None
    }
}  else {
    None
};
assert_eq!(value, Some(json!(1)));

こんな感じにわざわざ enum のvariantを剥がす処理を何度も書きます、地獄ですね。Value::pointer を使うと

use serde_json::{Value, json};

let obj = json!({"x": {"y": 1}});
assert_eq!(obj.pointer("/x/y"), Some(json!(1)));

このようにネストしたオブジェクトでもシュッと取ってこれます。前回PRを投げるきっかけになったRFC*1で記述されているpathと同じ記法*2で取ってくることができます。便利。 このメソッドに気づかずに自作しようと思ったのですが、上手く実装できなかったので同様のRFCを実装しているリポジトリ*3 を見たらこのValue::pointerを使っていました、偉い。

Value::pointer の実装を読んだ

自作できなかったのは心に来たので実装を読みました。最初実装に失敗した時は Iterator::fold を使おうとして失敗してたのですがforループで実装されていたので「ア〜〜〜〜」となりました。でもfold でもできそうな気がしたのでやったらできました、高階関数?関数型?に圧倒的感謝! しかし、fold だと /a/b/c/d/e/f/g/h/i みたいなケースで /a がなくても /b/c などを見に行きます、これが1万個のネストしたキーとかだったら辛いですね。 そこでIterator::try_fold を使うといい感じにearly-returnしてくれるっぽいです。

総括

ドキュメントにこんな乱文よりいい感じの説明があるので読みましょう