代码之家  ›  专栏  ›  技术社区  ›  Mark

当将特征方法和关联类型标记为专用化的默认值时,预期的输出类型将发生更改

  •  1
  • Mark  · 技术社区  · 6 年前

    我想实现一个 modulo 大多数操作 Rem 锈蚀类型:

    #![feature(specialization)]
    
    use std::ops::{Add, Rem};
    
    /// Define a modulo operation, in the mathematical sense.
    /// This differs from Rem because the result is always non-negative.
    pub trait Modulo<T> {
        type Output;
    
        #[inline]
        fn modulo(self, other: T) -> Self::Output;
    }
    
    /// Implement modulo operation for types that implement Rem, Add and Clone.
    // Add and Clone are needed to shift the value by U if it is below zero.
    impl<U, T> Modulo<T> for U
        where
            T: Clone,
            U: Rem<T>,
            <U as Rem<T>>::Output: Add<T>,
            <<U as Rem<T>>::Output as Add<T>>::Output: Rem<T>
        {
        default type Output = <<<U as Rem<T>>::Output as Add<T>>::Output as Rem<T>>::Output;
    
        #[inline]
        default fn modulo(self, other: T) -> Self::Output {
            ((self % other.clone()) + other.clone()) % other
        }
    }
    

    如果没有 default S,但与 违约 我得到

    error[E0308]: mismatched types
      --> main.rs:
       |
       |     default fn modulo(self, other: T) -> Self::Output {
       |                                          ------------ expected `<U as Modulo<T>>::Output` because of return type
       |         ((self % other.clone()) + other.clone()) % other
       |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected Modulo::Output, found std::ops::Rem::Output
       |
       = note: expected type `<U as Modulo<T>>::Output`
                  found type `<<<U as std::ops::Rem<T>>::Output as std::ops::Add<T>>::Output as std::ops::Rem<T>>::Output`
    

    我不明白为什么会这样。我需要 违约 因为我想专门为 Copy 类型。

    我每晚用1.29.0号铁锈。

    1 回复  |  直到 6 年前
        1
  •  1
  •   Shepmaster Tim Diekmann    6 年前

    这是问题的一个较小的复制品(一个 MCVE ):

    #![feature(specialization)]
    
    trait Example {
        type Output;
        fn foo(&self) -> Self::Output;
    }
    
    impl<T> Example for T {
        default type Output = i32;
    
        default fn foo(&self) -> Self::Output {
            42
        }
    }
    
    fn main() {}
    

    出现这个问题是因为这个实现的专门化可以选择专门化 Output foo 但这两者都不需要 :

    impl<T> Example for T
    where
        T: Copy,
    {
        type Output = bool;
    }
    

    在这种情况下,最初的实现 不再有意义了,它没有返回类型的值 Self::Output 不再。

    专业化的当前实现要求您同时考虑本地和全局,这是您必须在其中读取错误消息的上下文。这不太理想,但像这样的问题(以及许多更复杂的事情,我确信)是它还不稳定的部分原因。