Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

特定のfeatureが有効時に .unwrap() にする

メソッド にて説明している通り、 consume-question feature を有効にしている時に限り、 ! をメソッド末尾に付けることで ? を削除することが可能です。

これを利用すると、例えば ?unwrap の別名として利用できたりします。

例として、 unwrap featureが有効な時だけ ?.unwrap() に置き換える例を紹介します。Cargo.tomlのfeaturesが以下のように設定されているとします。

[dependencies]
hooq = { version = "*", features = ["consume-question"] }

# ..

[features]
unwrap = []

hooq.tomlに予めフレーバーを用意しておきます。末尾式や return に同様の置換を行われると困るため、 hook_targets の方で ? でのみ置き換わるように指定しておきます。

[unwrap]
method = """.unwrap()!"""
hook_targets = ["?"]

main.rsを次のようにします。

use hooq::hooq;

fn failable<T>(val: T) -> Result<T, String> {
    Ok(val)
}

#[cfg_attr(not(feature = "unwrap"), hooq(empty))]
#[cfg_attr(feature = "unwrap", hooq(unwrap))]
fn process(flag: bool) -> Result<(), String> {
    if flag {
        return Err("An error occurred".into());
    }

    let _ = failable(42)?;

    Ok(())
}

#[cfg_attr(not(feature = "unwrap"), hooq(empty))]
#[cfg_attr(feature = "unwrap", hooq(unwrap))]
fn main() -> Result<(), Box<dyn std::error::Error>> {
    process(false)?;

    Ok(())
}

unwrap featureがついていない時の展開結果は、emptyフレーバーが適用されるので何も変化が起きていません。

#![feature(prelude_import)]
#[macro_use]
extern crate std;
#[prelude_import]
use std::prelude::rust_2024::*;
use hooq::hooq;
fn failable<T>(val: T) -> Result<T, String> {
    Ok(val)
}
fn process(flag: bool) -> Result<(), String> {
    if flag {
        return Err("An error occurred".into());
    }
    let _ = failable(42)?;
    Ok(())
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
    process(false)?;
    Ok(())
}

一方で、 unwrap featureをつけている時の展開結果では、狙い通り .unwrap() に置き換わっています!

#![feature(prelude_import)]
#[macro_use]
extern crate std;
#[prelude_import]
use std::prelude::rust_2024::*;
use hooq::hooq;
fn failable<T>(val: T) -> Result<T, String> {
    Ok(val)
}
fn process(flag: bool) -> Result<(), String> {
    if flag {
        return Err("An error occurred".into());
    }
    let _ = failable(42).unwrap();
    Ok(())
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
    process(false).unwrap();
    Ok(())
}

本節では2つのことを紹介しました。

  • ?.unwrap() など特殊なものにも置き換えられること
  • #[cfg_attr(..., hooq(...))] でfeatureによってフック内容を変えられること

前者は(作者は詳しくありませんが、)unsafe Rustやno_std環境などでも ? を導入できる足がかりにできるかもしれません。後者は今回の例に限らず、featureを利用してデバッグ情報を調整する手段として有効活用できそうです!