我注意到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
的结构可以被包装并添加Debug的实现。
答案 0 :(得分:2)
您正在寻找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上的参考部分。
通过实施Deref
,它将起作用:
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