Option型を返す関数での利用
属性でフック対象判定を制御する 方法を紹介していましたが、イマイチピンとこなかったと思います。そもそも滅多に触ることはない設定だろうなと作者も考えています。
それでもなるべくイメージが付きやすい例ということで、 ( Result 型ではなく) Option 型にフックすることのみを目的とした設定を施してみましょう。
次の例では、main関数内に定義した関数にフックをしています。(ネストできることについては mod以下の関数に一括適用を参照してください。) Some であったときに中身を確認するメソッドを挿入したいというシナリオです。
tail_expr_idents: 今回、SomeにのみフックしたいのでSomeを指定ignore_expr_idents:Noneにフックを仕掛けるのは無駄なので(ほかに条件がそろっている時でも)Noneにはフックしないようにするresult_types:Option型関数の時は末尾式やreturnに来る値の型をフック対象だとみなすようになる
use std::fmt::Debug;
use hooq::hooq;
#[hooq]
#[hooq::method(.my_inspect())]
#[hooq::tail_expr_idents("Some")]
#[hooq::ignore_tail_expr_idents("None")]
#[hooq::result_types("Option")]
fn main() {
fn option_fn_1() -> Option<i32> {
// hook target
Some(42)
}
fn option_fn_2<T: Debug>(flag: bool, val: T) -> Option<T> {
// hook target
let _ = option_fn_1()?;
// hook target because the return type of the function is Option
if flag {
// hook target
Some(val)
} else {
// NOT hook target
None
}
}
fn result_fn_1() -> Result<i32, ()> {
// NOT hook target because the return type of the function is Result not Option
Ok(42)
}
fn result_fn_2() -> Result<i32, ()> {
// HOOK TARGET because of `?`
// so, #[hooq::skip_all] is needed
#[hooq::skip_all]
let _ = result_fn_1()?;
// NOT hook target because the return type of the function is Result not Option
Ok(42)
}
let _ = option_fn_1();
let _ = option_fn_2(true, 123);
let _ = result_fn_1();
let _ = result_fn_2();
}
trait MyInspect {
fn my_inspect(self) -> Self;
}
impl<T> MyInspect for Option<T>
where
T: Debug,
{
fn my_inspect(self) -> Self {
match self {
Some(val) => {
println!("Inspecting value: {:?}", val);
Some(val)
}
None => None,
}
}
}
前レシピのmod以下の関数に一括適用と同じぐらいのパズルになってしまいましたね…
展開結果は次のようになります。
#![feature(prelude_import)]
#[macro_use]
extern crate std;
#[prelude_import]
use std::prelude::rust_2024::*;
use std::fmt::Debug;
use hooq::hooq;
fn main() {
fn option_fn_1() -> Option<i32> {
Some(42).my_inspect()
}
fn option_fn_2<T: Debug>(flag: bool, val: T) -> Option<T> {
let _ = option_fn_1().my_inspect()?;
if flag { Some(val).my_inspect() } else { None }.my_inspect()
}
fn result_fn_1() -> Result<i32, ()> {
Ok(42)
}
fn result_fn_2() -> Result<i32, ()> {
let _ = result_fn_1()?;
Ok(42)
}
let _ = option_fn_1();
let _ = option_fn_2(true, 123);
let _ = result_fn_1();
let _ = result_fn_2();
}
trait MyInspect {
fn my_inspect(self) -> Self;
}
impl<T> MyInspect for Option<T>
where
T: Debug,
{
fn my_inspect(self) -> Self {
match self {
Some(val) => {
{
::std::io::_print(format_args!("Inspecting value: {0:?}\n", val));
};
Some(val)
}
None => None,
}
}
}
ともかく本節で主張したかったのは、基本的にはフック対象の型や識別子は Result, Ok, Err から変更することはないかもしれませんが、それでもhooqは対象となる型・識別子の設定を完全に固定しているわけではなく、一応設定変更可能にしているということです。
将来的に Tryトレイト 周りがstableになった時などに利用の幅が広がればと考えています。