Deref <T> trait
用于自定义解除引用运算符(*
)的行为。
如果实现Deref <T>
特征,则可以将智能指针视为参考。 因此,在引用上工作的代码也可以用在智能指针上。
常规引用
常规引用是一种指向某个值的指针,该值存储在其他地方。下面来看一个简单的例子来创建i32
类型值的引用,然后使用引用运算符和this
引用。
fn main()
{
let a = 20;
let b = &a;
if a==*b
{
println!("a and *b are equal");
}
else
{
println!("they are not equal");
}
}
执行上面示例代码,得到以下结果 -
a and *b are equal
在上面的例子中,a
保存i32
类型值20
,而b
包含a
变量的引用。 如果使用* b
,那么它代表值20
。因此,可以比较变量a
和* b
,它将返回真值。 如果使用&b
而不是* b
,则编译器会抛出错误“无法将{integer}与{&integer}进行比较”。
Box <T>
作为引用
Box <T>
指针可用作引用。
下面来看一个简单的例子:
fn main()
{
let a = 11;
let b = Box::new(a);
print!("Value of *b is {}",*b);
}
输出结果如下所示 -
Value of *b is 11
在上面的示例中,Box <T>
的行为与常规引用类似。 它们之间的唯一区别是b包含指向数据的框,而不是通过使用&
运算符引用该值。
智能指针作为引用
现在,创建类似于Box <T>
类型的智能指针,它们的行为与常规引用有一些不同。
Box <T>
可以定义为具有一个元素的元组结构,例如MyBox <T>
。
创建元组结构后,在MyBox <T>
类型上定义函数。
下面来看一个简单的例子:
struct MyBox<T>(T);
impl<T> MyBox<T>
{
fn example(y : T)->MyBox<T>
{
MyBox(y)
}
}
fn main()
{
let a = 8;
let b = MyBox::example(a);
print!("Value of *b is {}",*b);
}
执行上面示例代码,得到以下结果 -
在上面的例子中,创建了智能指针b
,但它不能被解除引用。 因此得出结论,无法取消类似于Box <T>
类型的自定义指针的引用。
实现Deref Trait
Deref Trait
在标准库中定义,该库用于实现名为deref
的方法。deref
方法借用self
并返回对内部数据的引用。
下面来看一个简单的例子:
struct MyBox<T>
{
a : T,
}
use :: std::ops::Deref;
impl<T> Deref for MyBox<T>
{
type Target = T;
fn deref(&self) ->&T
{
&self.a
}
}
fn main()
{
let b = MyBox{a : 10};
print!("{}",*(b.deref()));
}
执行上面示例代码,得到以下结果 -
10
程序说明
Deref trait
在MyBox
类型上实现。Deref trait
实现deref()
方法,deref()
方法返回a
变量的引用。type Target = T;
是Deref trait
的关联类型。关联类型用于声明泛型类型参数。- 创建了
MyBox
类型的实例 -b
。 - 通过使用
MyBox
类型的实例b.deref()
调用deref()
方法,然后取消引用从deref()
方法返回的引用。
Deref强制
Deref
强制是将实现Deref trait
的引用转换为Deref
可以将原始类型转换为的引用的过程。Deref
强制是对函数和方法的参数执行的。- 当将特定类型的引用传递给与函数定义中的参数类型不匹配的函数时,
Deref
强制自动发生。
下面来看一个简单的例子:
struct MyBox<T>(T);
use :: std::ops::Deref;
impl<T> MyBox<T>
{
fn hello(x:T)->MyBox<T>
{
MyBox(x)
}
}
impl<T> Deref for MyBox<T>
{
type Target = T;
fn deref(&self) ->&T
{
&self.0
}
}
fn print(m : &i32)
{
print!("{}",m);
}
fn main()
{
let b = MyBox::hello(5);
print(&b);
}
执行上面示例代码,得到以下结果 -
5
在上面的例子中,使用参数&b
调用print(&b)
函数,它是&Box <i32>
的引用。 在这种情况下,实现Deref trait
,通过Deref
强制过程将&Box <i32>
转换为&i32
。
Derif强制与可变性的相互作用
到目前为止,使用Deref Trait
覆盖不可变引用上的*
运算符,可以使用DerefMut Trait
覆盖可变引用上的*
运算符。
Rust在以下三种情况下执行Deref
强制:
- 当T:
Deref <Target = U>
其中T
和U
是不可变引用时,则&T
转换为&U
类型。 - 当T:
DerefMut <Target = U>
,其中T
和U
是可变引用时,则&mut T
被转换为&mut U
。 - 当T:
Deref <Target = U>
,其中T
是可变引用而U
是不可变引用,则&mut T
被转换为&U
。