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

有没有可能做我自己的包装盒?

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

    我注意到 Box<T> 实现所有 T 实现并且可以透明地使用。例如:

    let mut x: Box<Vec<u8>> = Box::new(Vec::new());
    x.push(5);
    

    我也希望能这样做。

    这是一个用例:

    假设我正在编写使用x轴和y轴操作的函数。我正在使用值来更改那些类型为数字但只属于一个或另一个轴的轴。

    如果试图对不属于好轴的值执行操作,我希望编译器失败。

    例子:

    let x = AxisX(5);
    let y = AxisY(3);
    let result = x + y; // error: incompatible types
    

    我可以通过构造一个结构来包装数字:

    struct AxisX(i32);
    struct AxisY(i32);
    

    但那不能让我获得所有的方法 i32 提供类似 abs() . 例子:

    x.abs() + 3 // error: abs() does not exist
    // ...maybe another error because I don't implement the addition...
    

    另一个可能的用例:

    您可以为自己指定另一个库的结构,并实现或派生任何您想要的内容。例如:不派生 Debug 可以包装并添加调试实现。

    1 回复  |  直到 6 年前
        1
  •  2
  •   Tim Diekmann suresh madaparthi    6 年前

    你在找 std::ops::Deref :

    除了用于(一元)的显式解引用操作之外 * 不可变上下文中的运算符, Deref 在许多情况下编译器也隐式使用。这个机制叫做 Deref coercion '.在可变的上下文中, DerefMut 使用。

    进一步:

    如果 T 工具 Deref<Target = U> x 是类型的值 T ,然后:

    • 在不可变的上下文中, *x 在非指针类型上等于 *Deref::deref(&x) .
    • 类型值 &T 被强制为类型的值 &U
    • T 隐式实现该类型的所有(不可变)方法 U .

    有关详细信息,请访问 the chapter in The Rust Programming Language 以及 the dereference operator , method resolution type coercions .

    通过实施 德雷夫 它将起作用:

    impl Deref for AxisX {
        type Target = i32;
    
        fn deref(&self) -> &i32 {
            &self.0
        }
    }
    
    x.abs() + 3
    

    你可以在 Playground .

    但是,如果从基础类型调用函数( i32 在这种情况下,返回类型将保留为基础类型。因此

    assert_eq!(AxisX(10).abs() + AxisY(20).abs(), 30);
    

    会过去的。要解决此问题,您可以覆盖一些您需要的方法:

    impl AxisX {
        pub fn abs(&self) -> Self {
            // *self gets you `AxisX`
            // **self dereferences to i32
            AxisX((**self).abs())
        }
    }
    

    这样,上面的代码就失败了。 Take a look at it in action .