首页 > 解决方案 > 锈中的“可选特征绑定”功能

问题描述

我想为函数提供类似可选特征的东西。如果在哪里T实现该类型 - 做某事。

fn test<T: Eq + ?Debug>(a:T, b:T){
    if a!=b{
        println!("Not equal!");
        if (T impl Debug){
            println!("{:?} != {:?}", a, b);
        }
    }
}

标签: rust

解决方案


正如@user4815162342 所评论的,使用专业化,这是可能的。

我将提供一种与他们在评论中指定的方法略有不同的方法,以保持与if ... { ... }原始代码中相同的设置。

这个想法是有一个AsMaybeDebug具有关联类型的特征Debug,它总是实现Debug和一个函数从&Selfto Option<&Self::Debug>

trait AsMaybeDebug {
    type Debug: Debug;
    fn as_maybe_debug(&self) -> Option<&Self::Debug>;
}

在此之后,我们为 all 创建一个默认的 impl T,调试类型为!, never 类型,并且总是 return None

impl<T> AsMaybeDebug for T {
    default type Debug = !;
    default fn as_maybe_debug(&self) -> Option<&Self::Debug> {
        None
    }
}

您可以选择任何始终实现Debug但仍返回的类型,而不是 never 类型None

之后我们专门T: Debug返回Self

impl<T: Debug> AsMaybeDebug for T {
    type Debug = Self;
    fn as_maybe_debug(&self) -> Option<&Self::Debug> {
        Some(self)
    }
}

最后,test我们只需调用as_maybe_debug并检查是否T: Debug

fn test<T: Eq>(a: T, b: T){
    if a != b {
        println!("Not equal!");
        
        if let (Some(a), Some(b)) = (a.as_maybe_debug(), b.as_maybe_debug()) {
            println!("{:?} != {:?}", a, b);
        }
    }
}

您可以在操场上检查它是否可以工作,并且生成的程序集test_non_debug没有任何调试调用,只有对std::io::_print.

不幸的是,无法在after call中检索原始文件ab内部文件。ifas_maybe_debug

这是由于<Self as AsMaybeDebug>::Debug不能转换回Self. 这可以修复,但不容易,因为它需要标准库的更新。

要求AsMaybeDebug::Debug: AsRef<Self>不起作用有两个原因:

    1. 还没有impl<T> AsRef<T> for T,我想这是因为专业化仍然不完整。
    1. 还没有impl<T> AsRef<T> for !。不确定是否可以通过专业化来制作这个 impl,但它是必需的。

此外,虽然specialization可能不健全,但我相信 trait 及其 impls 不能用于不健全,你需要一个特定的设置才能从中产生不健全,这是缺乏的。


推荐阅读