繁体   English   中英

如何编写一个方法来包装我的类型中的任何值,该方法可以多次调用而不需要类型注释?

[英]How can I write a method to wrap any value in my type that can be called multiple times without requiring type annotations?

我写了一个类型Wrapper<T> ,其中包含一个T值:

struct Wrapper<T>(T);

我想要一个to_wrap方法,它允许我编写这样的代码,其中bWrapper<i32>cWrapper<i32>

let a = 12i32;
let b = a.to_wrap();
let c = b.to_wrap();

我希望v.to_wrap()始终生成一个Wrapper<T> ,其中 T不是Wrapper 如果vWrapper<T>v.to_wrap()也将是具有相同值的Wrapper<T>

我写的最接近我的想法的代码是:

#![feature(specialization)]

#[derive(Debug)]
struct Wrapper<T>(T);

trait ToWrapper<W> {
    fn to_wrap(self) -> W;
}

impl<T> ToWrapper<Wrapper<T>> for T {
    default fn to_wrap(self) -> Wrapper<T> {
        Wrapper(self)
    }
}

impl<T> ToWrapper<Wrapper<T>> for Wrapper<T> {
    fn to_wrap(self) -> Self {
        self
    }
}

fn main() {
    let a = 1i32;
    println!("{:?}", a);
    let a = 1.to_wrap();
    println!("{:?}", a);
    let a: Wrapper<i32> = 1.to_wrap().to_wrap();
    // let a = 1.to_wrap().to_wrap();
    // boom with `cannot infer type`
    println!("{:?}", a);
}

操场

如果我从let a: Wrapper<i32> = 1.to_wrap().to_wrap()删除类型注释,则会出现编译错误:

error[E0282]: type annotations needed
  --> src/main.rs:27:9
   |
27 |     let a = 1.to_wrap().to_wrap();
   |         ^
   |         |
   |         cannot infer type
   |         consider giving `a` a type

我希望 Rust 编译器自动派生1.to_wrap().to_wrap() 我怎样才能写出正确的版本,或者为什么不能写出来?

我不相信您现在可以使用专业化来实现实现单个特征的目标。

您的特征定义允许同一类型的特征的多个实现:

trait ToWrapper<W> {
    fn to_wrap(self) -> W;
}

impl ToWrapper<i32> for u8 {
    fn to_wrap(self) -> i32 {
        i32::from(self)
    }
}

impl ToWrapper<i16> for u8 {
    fn to_wrap(self) -> i16 {
        i16::from(self)
    }
}

有了这样的设置,就不可能知道to_wrap的结果类型应该是什么; 您将始终需要以某种方式提供输出类型。 然后,您尝试在未知类型上调用to_wrap会产生另一个未知类型,从而使问题to_wrap

通常,使用关联类型将是解决方案,但由于它们与专业化的交互方式,您无法切换到此处。

也可以看看:

你可以在每晚实现这样的事情,不使用专业化,而是使用两个不同的特征和一个自动特征来区分它们。

#![feature(auto_traits)]
#![feature(negative_impls)]

auto trait IsWrap {}

#[derive(Debug)]
struct Wrapper<T>(T);

impl<T> !IsWrap for Wrapper<T> {}

trait ToWrapper: Sized {
    fn to_wrap(self) -> Wrapper<Self>;
}

impl<T: IsWrap> ToWrapper for T {
    fn to_wrap(self) -> Wrapper<T> {
        Wrapper(self)
    }
}

trait ToWrapperSelf {
    fn to_wrap(self) -> Self;
}

impl<T> ToWrapperSelf for Wrapper<T> {
    fn to_wrap(self) -> Self {
        self
    }
}

fn main() {
    let a = 1.to_wrap();
    println!("{:?}", a);
    let a = 1.to_wrap().to_wrap(); 
    println!("{:?}", a);
}

chabapok 的建议一样,您不能使用这种技术来编写一个泛型函数,该函数在给定一种类型时以一种方式运行,而在另一种类型下以另一种方式运行(尽管请参阅下面的链接)。 但是当编译器知道具体类型但程序员不知道具体类型时,您可以使用它——宏作为一个可能的用例出现在脑海中。

它还有一个优点,那就是在任何类型上调用哪个to_wrap方法时都不可能存在歧义。 每种类型最多有一个to_wrap方法,因为Wrapper s 只有ToWrapperSelf::is_wrap Wrapper s 只有ToWrapper::is_wrap

另外一个DIS优点是!IsWrapWrapper<T>是“感染性”:含有或可能含有任何类型Wrapper<T>将自动!IsWrap 如果您对此类类型调用.to_wrap() ,编译器将无法找到该方法并会发出错误。 如果这是一个问题,您可以为这些类型手动实现IsWrap ,但寻找另一个不那么脆弱的解决方案可能会更加谨慎。

(上述唯一的例外是Box<Wrapper<T>> :您可以在其上调用ToWrapperSelf::to_wrap以获取Wrapper<T> 。发生这种情况是由于自动解引用规则并且因为Box是特殊的。)

也可以看看

#[derive(Debug)]
struct Wrapper<T>(T);

trait ToWrapper<W> {
    fn to_wrap(self) -> Wrapper<W>;
}

impl<T> ToWrapper<T> for T {
    fn to_wrap(self) -> Wrapper<T> {
        Wrapper(self)
    }
}

impl<T> Wrapper<T> {
    fn to_wrap(self) -> Wrapper<T> {
        self
    }
}

fn main() {
    let a = 1i32;
    println!("{:?}", a);
    let a = 1.to_wrap();
    println!("{:?}", a);
    let a: Wrapper<i32> = 1.to_wrap().to_wrap();
    let b = 1.to_wrap().to_wrap();
    println!("{:?}", a);
    println!("{:?}", b);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM