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

Rust 如何编写一个方法来包装我的类型中可以多次调用而不需要类型注释的任何值?,rust,Rust,我编写了一个类型包装器,其中包含一个T值: 结构包装器; 我想要一个包装的方法,它允许我写这样的代码,其中b是包装器,c是包装器: 设a=12i32; 设b=a,以便于包装; 设c=b,以便于包装; 我希望v.to_wrap始终生成一个包装,其中T不是包装。如果v是包装器,那么v.to_wrap也将是具有相同值的包装器 我写的最接近我想法的代码是: ![特色专业化] [衍生博客] 结构包装器; 特征拖缆机{ fn到_wrapself->W; } 用于T的impl拖缆机{ 默认fn为_wrapse

我编写了一个类型包装器,其中包含一个T值:

结构包装器; 我想要一个包装的方法,它允许我写这样的代码,其中b是包装器,c是包装器:

设a=12i32; 设b=a,以便于包装; 设c=b,以便于包装; 我希望v.to_wrap始终生成一个包装,其中T不是包装。如果v是包装器,那么v.to_wrap也将是具有相同值的包装器

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

![特色专业化] [衍生博客] 结构包装器; 特征拖缆机{ fn到_wrapself->W; } 用于T的impl拖缆机{ 默认fn为_wrapself->Wrapper{ 包装器 } } 用于包装的impl拖缆机{ fn到_wrapself->Self{ 自己 } } fn干线{ 设a=1i32; println!{:?},a; 设a=1.0,以便于包装; println!{:?},a; 设a:Wrapper=1.to_wrapp.to_wrapp; //设a=1.to_wrap.to_wrap; //带有`的boom无法推断类型` println!{:?},a; } 如果我从let a:Wrapper=1.to_wrap.to_wrap删除上的类型注释,则会出现编译错误:

错误[E0282]:需要类型批注 ->src/main.rs:27:9 | 27 |设a=1.to_wrap.to_wrap; | ^ | | |无法推断类型 考虑给予“A”型
我希望Rust编译器自动派生1.to_wrap.to_wrap的类型。我怎样才能写出正确的版本,或者为什么不可能写出正确的版本?

我不相信在这个时候,你可以通过专业化来实现你的目标

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

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)
    }
}
有了这样的设置,就不可能知道要包装的结果类型应该是什么;您总是需要以某种方式提供输出类型。然后,通过尝试调用一个未知类型上的_wrap来产生另一个未知类型,从而使问题更加复杂

通常情况下,使用关联类型是解决方案,但是您不能在这里切换到那些类型,因为它们如何与专门化交互

另见:


我不相信你能在这个时候通过专业化来实现你的目标

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

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)
    }
}
有了这样的设置,就不可能知道要包装的结果类型应该是什么;您总是需要以某种方式提供输出类型。然后,通过尝试调用一个未知类型上的_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);
}
与之一样,您不能使用此技术编写一个泛型函数,该函数在给定一种类型时以一种方式运行,在给定另一种类型时以另一种方式运行,尽管请参见下面的链接。但是,当编译器知道具体类型而程序员不知道具体类型时,可以使用它——宏是一种可能的用例

它还有一个优点,即在任何类型上调用tou wrap方法时,都不存在可能的歧义。每个类型最多有一个to_wrap方法,因为包装器只有towrapperlf::is_wrap,而非包装器只有ToWrapper::is_wrap

另一个缺点是!IsWrap for Wrapper具有感染性:任何包含或可能包含包装的类型也将被自动删除!IsWrap。如果对此类类型调用.to_wrap,编译器将无法找到该方法,并将发出错误。如果这是一个问题,您可以为这些类型手动实现IsWrap,但寻找另一个不那么脆弱的解决方案可能更为谨慎

上面提到的唯一例外是Box:您可以调用towraperself::对其进行包装以获得包装器。发生这种情况的原因是自动取消引用规则和

另见 上述解决方案类似于。 有类似的专业化,但没有真正的味道。我对这个问题的回答可以与这个答案结合起来,创建特性和通用函数,透明地分派包装器和非包装器,即使你不能充分利用专门化的力量。
你可以在夜间完成类似的事情,不使用专门化,而是使用两种不同的特性和一种自动特性来区分它们

#![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);
}
与之一样,您不能使用此技术编写一个泛型函数,该函数在给定一种类型时以一种方式运行,在给定另一种类型时以另一种方式运行,尽管请参见下面的链接。但是,当编译器知道具体类型而程序员不知道具体类型时,可以使用它——宏是一种可能的用例

它还有一个优点,即在任何类型上调用tou wrap方法时,都不存在可能的歧义。每个类型最多有一个to_wrap方法,因为包装器只有towrapperlf::is_wrap,而非包装器只有ToWrapper::is_wrap

另一个缺点是!IsWrap for Wrapper具有感染性:任何包含或可能包含包装的类型也将被自动删除!IsWrap。如果对此类类型调用.to_wrap,编译器将无法找到该方法,并将发出错误。如果这是一个问题,您可以为这些类型手动实现IsWrap,但寻找另一个不那么脆弱的解决方案可能更为谨慎

上面提到的唯一例外是Box:您可以调用towraperself::对其进行包装以获得包装器。发生这种情况的原因是自动取消引用规则和

另见 上述解决方案类似于。 有类似的专业化,但没有真正的味道。我对这个问题的回答可以与这个答案结合起来,创建特性和通用函数,透明地分派包装器和非包装器,即使你不能充分利用专门化的力量。
请用一些词来解释您的解决方案是如何工作的,并找出它可能存在的任何弱点。谢谢。我发现在定义fn foovalue:ToWrapper;这样的泛型函数时会出现意外行为;;当我给它一个值:Wrapper时,它将使用::to_wrap而不是Wrapper::to_wrap。请用一些词来解释您的解决方案是如何工作的,并找出它可能存在的任何弱点。谢谢。我发现在定义fn foovalue:ToWrapper;这样的泛型函数时会出现意外行为;;当我给它一个值:Wrapper时,它会使用::to_wrap而不是Wrapper::to_wrap。这种方法的缺点是它会将任何包含Wrapper的结构(例如Rc)视为Wrapper,这可能是不需要的。谢谢。Auto-trait对我来说是一个新事物。这种方法的缺点是它会将任何包含Wrapper的结构(例如Rc)视为Wrapper,这可能是不受欢迎的。谢谢。自动特征对我来说是一个新事物。谢谢。我已经尝试过使用关联类型,正如您所说,尽管我对类型进行了注释,但它无法兼容。谢谢。我已经尝试过使用关联类型,正如您所说的,尽管我对类型进行了注释,但它无法兼容。