as_ref()で構造体メンバの参照取得

Rustの構造体で、nullableなメンバは以下のようにOption型を利用する記述になります。

struct Friend {
  name: Option<String>
}

let john = Friend { name: Some("John") };

この変数Johnを関数に渡す際、イミュータブルな参照として&johnを渡すことを第一に考えるケースが多いでしょう。実体を渡してしまうとそこでmoveしてしまい、後続の処理で利用できなくなるのはRustの基本ルールです。

ところが、以下のように素朴にメンバーにアクセスするとエラーになります。

fn (friend: &Friend) -> Option<String> {
  let name = friend.name.map(|n| String::from(n))?;
  // ...
}

一見コード上は問題なく見えるのですが、Optionなど一部の型については、構造体のインスタンスを参照で渡しても、メンバーアクセス時に実体を取得しに行く挙動になります。
このようなケースでは、以下のようにas_ref()メソッドを経由すると、Option -> Option<&T>に変換され、意図したとおり借用アクセスになります。

  let name = friend.name.as_ref().map(|n| String::from(n))?;

実務上、NOTNULL制約のないDBデータなどはOptionになることが多いため、取り扱いがやや面倒なポイントと言えます。

as_deref()

頻度が少なそうなものの、特定のケースでは as_deref()が必要になります。

Box<[T]>のOptionから[T]を取り出すケースでBoxのDerefが必要になり、as_deref()が求められました。

Box<[T]>は意図的に使わない限りほぼ遭遇しませんが、Box<[T]>の取り扱いはドキュメントが乏しいのでやや苦労します。

⁋ 2020/12/27↻ 2024/11/07
中馬崇尋
Chuma Takahiro