How can I specialize a method for a specific generic type?

我与影子孤独终老i 提交于 2020-07-03 08:53:11

问题


I want to define methods for Untyped and Unit or basically every type, but I want to specialize a few methods just for Unit.

The problem is that Rust doesn't allow two implementations here. I am using Rust 1.9, do I need to enable specialzation or is this just not possible?

use num::Float; // 0.2.1
use std::marker::PhantomData;

#[derive(Copy, Clone, Eq, PartialEq)]
pub struct Untyped;

#[derive(Copy, Clone, Eq, PartialEq)]
pub struct Unit;

struct Vector<T, Type> {
    data: [T; 3],
    _m: PhantomData<Type>,
}

impl<T> Vector<T, Unit>
where
    T: Float,
{
    fn length(&self) -> T {
        println!("SPECIAL");
        T::one()
    }
}

impl<T, Type> Vector<T, Type>
where
    T: Float,
{
    fn length(&self) -> T {
        println!("NON SPECIAL");
        T::one()
    }
}

fn main() {
    let v = Vector::<f32, Untyped> {
        data: [1., 2., 3.],
        _m: PhantomData,
    };
    let v1 = Vector::<f32, Unit> {
        data: [1., 2., 3.],
        _m: PhantomData,
    };
    let l = v.length();
    let l1 = v1.length();
}
error[E0592]: duplicate definitions with name `length`
  --> src/main.rs:19:5
   |
19 | /     fn length(&self) -> T {
20 | |         println!("SPECIAL");
21 | |         T::one()
22 | |     }
   | |_____^ duplicate definitions for `length`
...
29 | /     fn length(&self) -> T {
30 | |         println!("NON SPECIAL");
31 | |         T::one()
32 | |     }
   | |_____- other definition for `length`

回答1:


You are trying to specialize a method defined in an inherent impl, rather than specializing a method defined in a trait. This appears to not be supported at the moment, even after adding default to the "non special" length method. RFC 1210 mentions inherent impls as a possible extension, which I understand as not being considered for implementation at the moment.

As a workaround, consider moving your method to a trait. This requires specialization to be enabled to work, so you'll need to use a nightly compiler until the feature is stabilized.

Instead of defining the default implementation on the trait, we define it in the general impl. We need to add the default contextual keyword to that function.

#![feature(specialization)]

trait VectorExt<T>
where
    T: Float,
{
    fn length(&self) -> T;
}

impl<T, Type> VectorExt<T> for Vector<T, Type>
where
    T: Float,
{
    default fn length(&self) -> T {
        println!("NON SPECIAL");
        T::one()
    }
}

impl<T> VectorExt<T> for Vector<T, Unit>
where
    T: Float,
{
    fn length(&self) -> T {
        println!("SPECIAL");
        T::one()
    }
}

// This `impl` is not strictly necessary,
// but it will let users of your type
// use the `length` method
// without having to `use` the `VectorExt` trait.
impl<T, Type> Vector<T, Type>
where
    T: Float,
{
    fn length(&self) -> T
    where
        Self: VectorExt<T>,
    {
        VectorExt::<T>::length(self)
        // can also be written as: <Self as VectorExt<T>>::length(self)
    }
}

playground



来源:https://stackoverflow.com/questions/38024059/how-can-i-specialize-a-method-for-a-specific-generic-type

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!