You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust:如何判断类型是否为Result/实现Try trait?宏方案求助

Rust活动日志器实现:类型判断与宏封装问题

我刚接触Rust,需要了解该语言的类型检查机制,目标是实现一个活动日志器,用来捕获并记录函数的执行时长与结果。以下是我的简化实现:

struct Activity {
    name: String,
    start_time: std::time::Instant,
}

impl Activity {
    fn begin(name: &str) -> Self {
        println!("Activity started: {}", name);
        Activity {
            name: name.to_string(),
            start_time: std::time::Instant::now(),
        }
    }

    fn end_ok(&self) {
        let duration = self.start_time.elapsed().as_millis();
        println!("Activity ended: {}, Status: Success, Duration: {}", self.name, duration);
    }

    fn end_error<T: ToString>(&self, error: &T) {
        let duration = self.start_time.elapsed().as_millis();
        println!(
            "Activity ended: {}, Status: Fail, Duration: {}, Message: {}",
            self.name,
            duration,
            error.to_string()
        );
    }
}

type MyResult = Result<(), String>;

fn test1() -> Result<(), Box<dyn std::error::Error>> {
    test2()?;
    Ok(())
}

fn test2() -> MyResult {
    Err("oops".to_string())
}

fn main() {
    let activity = Activity::begin("TestActivity");

    match test1() {
        Ok(_) => activity.end_ok(),
        Err(error) => activity.end_error(&error),
    }
}

当前实现虽然能用,但手动分析每个结果并构建结果链的方式太繁琐,我更想使用?运算符,但这需要对结果处理进行封装。我尝试用proc_macro_attribute来做封装,但遇到了判断函数返回类型的难题。

我的目标是识别函数块的返回值类型:如果是Result<_, _>且返回Err,就调用end_error(error);否则调用end_ok()。以下是我尝试的宏实现:

extern crate proc_macro;

use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, ItemFn, LitStr, ReturnType};

#[proc_macro_attribute]
pub fn activity_logger(attr: TokenStream, item: TokenStream) -> TokenStream {
    let logger_name = parse_macro_input!(attr as LitStr).value();
    let input_fn = parse_macro_input!(item as ItemFn);
    let fn_name = &input_fn.sig.ident;
    let fn_block = &input_fn.block;
    let fn_return_type = &input_fn.sig.output;
    
    let output = match fn_return_type {
        ReturnType::Type(_, _) => quote! {
            fn #fn_name() #fn_return_type {
                let activity = Activity::begin(#logger_name);

                let result = (|| #fn_block)();
                
                // C#风格伪代码开始
                if result is Result<_, _> {
                    match result {
                        Ok(_) => activity.end_ok(),
                        Err(error) => activity.end_error(error),
                    }
                } else {
                    activity.end_ok();
                }
                // C#风格伪代码结束

                result
            }
        },
        ReturnType::Default => quote! {
            fn #fn_name() {
                let activity = Activity::begin(#logger_name);

                #fn_block
                
                activity.end_ok();
            }
        },
    };

    output.into()
}

有没有办法在运行时判断一个对象是否实现了Try trait或者是否为Result<_, _>?或者用宏能否解决这个问题?

我目前找到的唯一识别返回类型的方式是通过ReturnType::Type(_, ty)提取类型名,或者用std::any::type_name,但这并不理想,因为结果类型可能被重命名。

我还尝试用trait来解决,但遇到了问题:

  • Rust不允许这类代码,因为存在实现歧义:
trait IsResult {
    const IS_RESULT: bool;
}

impl<T, E> IsResult for Result<T, E> {
    const IS_RESULT: bool = true;
}

impl<T> IsResult for T {
    const IS_RESULT: bool = false;
}
  • 而且Rust的trait和其他语言的接口不同,以下方法也无效:
trait Loggable {
    fn can_log(&self) -> bool;
}

trait LoggableResult: Loggable {
    fn can_log(&self) -> bool;
}

impl<T> Loggable for T {
    fn can_log(&self) -> bool {
        false
    }
}

impl<T, E> LoggableResult for Result<T, E> {
    fn can_log(&self) -> bool {
        true
    }
}

fn can_log(value: &dyn Loggable) -> bool {
    value.can_log()
}

fn test() {
    let test1_result = 123;
    let test1 = can_log(&test1_result); // false
    let test2_result: Result<(), String> = Result::Err("oops".to_string());
    let test2 = can_log(&test2_result); // false
}

内容的提问来源于stack exchange,提问作者evgenxpp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 20:05:55