当前位置:网站首页>Rust dereference
Rust dereference
2022-08-09 23:54:00 【hebiwen95】
“解引用(Deref)”是“引用(Ref)”的反操作.比如说,we have reference typeslet p: &T;,那么可以用*Symbol performs dereference operation,let v: T = *p;.如果p的类型是&T, 那么*p的类型就是T.
自定义解引用
解引用操作,可以被自定义.方法是,实现标准库中的std::ops::Deref和std::ops::DerefMut这两个 trait.
Deref的定义如下所示,DerefMutThe only difference is that what is returned is&mut型引用,都是类似的,Therefore, no further introduction.
pub trait Deref {
type Target: ?Sized;
fn deref(&self) -> &Self::Target;
}
pub trait DerefMut: Deref {
fn deref_mut(&mut self) -> &mut Self::Target;
}
这个 trait has an associated type Target,代表解引用之后的目标类型.
比如说,标准库中,实现了String向str的解引用转换:
impl ops::Deref for String {
type Target = str;
#[inline]
fn deref(&self) -> &str {
unsafe { str::from_utf8_unchecked(&self.vec) }
}
}
Please pay attention to the type here,deref() 方法返回的类型是 &Target,而不是 Target.
If there is variables的类型为String,*s 的类型并不等于 s.deref() 的类型.
*s的类型实际上是 Target,即str.&*s的类型为&str.
而 s.deref() 的类型为 &Target,即 &str.它们的关系为:
s : String
&s : &String
Target : str
s.deref() : &str
*s : str
&*s : &str
标准库中,There are many common types,实现了这个 Deref 操作符.比如 Vec<T>、
String、Box<T>、Rc<T>、Arc<T>等.它们都支持“解引用”这个操作.
从某种意义上来说,They might appear in the form of special“指针”,(like a fat pointer,is a pointer with extra metadata).
- &[T]是指针,points to an array slice;
- &str是“指针”,points to a string slice;
They contain not only pointers to data,Also carries the length information of the pointed data,but they have no effect on the array of pointers to/String section no ownership,Not responsible for the allocation and release of memory space.
- Box<T>是“指针”,points to an object allocated on the heap;
- Vec<T>是“指针”,Points to a group of sequentially arranged heap-allocated objects of the same type;
- String是“指针”,Points to a heap-allocated byte array,The content stored in it is legal utf8 字符序列.
They both have ownership of the content they point to,manages the allocation and release of the memory space they point to.
- Rc<T>和Arc<T>in some form“指针”,They provide a“共享”的所有权,After all reference counted pointers are destroyed,The memory space they point to will be freed.
custom dereference operator,Allows users to define a variety of“智能指针”,完成各种各样的任务.Combined with the compiler“自动”dereference mechanism,非常有用.Below we explain what is“自动解引用”.
自动解引用
RustThe design concept has always been“显式比隐式好”.Code should express its behavior as explicitly as possible,avoid out of sight“自动”帮我们做一些事情.
凡事都有例外.RustOne of the most easily misunderstood by beginners“隐式”behavior is this“自动解引用”.What is automatic dereferencing?,下面用一个示例来说明:
fn main() {
let s = "hello";
println!("length: {}", s.len());
println!("length: {}", (&s).len());
println!("length: {}", (&&&&&&&&&&&&&s).len());
}
编译发现,可以编译成功.我们知道,len这个方法的签名是:
fn len(&self) -> usize
它接受的参数是&str,因此我们可以用 UFCS The syntax is called like this:
println!("length: {}", str::len(&s));
但是,我们如果使用&&&&&&&&&&strType members to invoke the method,也是可以的.原因就是,RustThe compiler does it for us implicitly deref 调用,when it can't find the member method,it will automatically try to usederefFind the method after the method,一直循环下去.编译器在&&&strtype not foundlen方法,just try to put itderef,变成&&str类型,再寻找len方法,还是没找到,那么继续deref,变成&str,现在找到len方法了,And then call this method.
自动deref的规则是,如果类型T可以解引用为U,即T: Deref<U>,则&T可以转为&U.
The usefulness of automatic dereferencing
用Rc这个“智能指针”举例.Rc实现了Deref:
impl<T: ?Sized> Deref for Rc<T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &T {
&self.inner().value
}
}
它的 Target type is its generic parameter T.What's the benefit of this design?,Let's look at the following usage:
use std::rc::Rc;
fn main() {
let s = Rc::new(String::from("hello"));
println!("{:?}", s.bytes());
}
我们创建了一个指向String类型的Rc指针,并调用了bytes()方法.Isn't it a little strange here?
RcThe type itself does notbytes()方法,So the compiler will try to automaticallyderef,试试s.deref().bytes().Stringtype doesn'tbytes()方法,但是String可以继续deref,Then try agains.deref().deref().bytes().这次在str类型中,找到了bytes()方法,于是编译通过.
我们实际上通过Rc类型的变量,调用了str类型的方法,The existence of the smart Pointers like a transparent.This is the automaticDeref的意义.
In fact, the following writing looks the same in the compiler:
use std::rc::Rc;
use std::ops::Deref;
fn main() {
let s = Rc::new(String::from("hello"));
println!("length: {}", s.len());
println!("length: {}", s.deref().len());
println!("length: {}", s.deref().deref().len());
println!("length: {}", (*s).len());
println!("length: {}", (&*s).len());
println!("length: {}", (&**s).len());
}
注意:我们可以写let p = &*s;,It can create a pointer to the internalString的指针.This spelling does not mean
let tmp = *s;
let x = &tmp;
因为这个tmp的存在,它表达的是move语义.也不等于
let x = &{*s};
This brace introduces new scope,同样也是move语义.
Sometimes manual handling is required
如果说,What should I do if the method in the smart pointer conflicts with the method of its internal members??The compiler will call the current best matching type first,without performing automatic deref,这种情况下,we can only do it manually deref To express our needs.
比如说,Rc类型和String类型都有clone方法,But they perform different tasks.Rc::clone()What it does is make a copy of the reference counted pointer,把引用计数加1.String::clone()What it does is make a copy of the string.示例如下:
use std::rc::Rc;
use std::ops::Deref;
fn type_of(_: ()) { }
fn main() {
let s = Rc::new(Rc::new(String::from("hello")));
let s1 = s.clone(); // (1)
//type_of(s1);
let ps1 = (*s).clone(); // (2)
//type_of(ps1);
let pps1 = (**s).clone(); // (3)
//type_of(pps1);
}
在以上的代码中,位置(1)处,s1的类型为Rc<Rc<String>>,位置(2)处,ps1的类型为Rc<String>,位置(3)处,pps1的类型为String.
一般情况,在函数调用的时候,The compiler will try to dereference automatically for us.但在其它情况下,The compiler doesn't automatically insert auto-dereference code for us.比如,以String和 &str类型为例:
fn main() {
let s = String::new();
match &s {
"" => {}
_ => {}
}
}
This code compiles with an error,错误信息为:
mismatched types:
expected `&collections::string::String`,
found `&'static str`
match The latter variable type is &String,The variable type of match branch is &str,In this case, we need to manually complete the type conversion.为了将&String类型转换为&str类型,Manual type conversion words what way?
参考答案:
- match s.as_ref(). This method is the most common and intuitive method.
- match s.borrow().为了使用这个方法,我们必须引入Borrow trait.That is, you need to add codeuse std::borrow::Borrow;.
- match s.deref(). This method through the active callderef()方法,achieve the purpose of type conversion.此时我们需要引入Deref traitside can be compiled by,即加上代码use std::ops::Deref;.
- match &*s. 我们可以通过*s运算符,can also be forced to callderef()方法,same as above.
- match &s[..].This plan is also possible,这里利用了String重载的Index操作.
总结
RustSome operators are allowed to have user-defined behavior,like in other languages“操作符重载”.where dereference is a very important operator,It allows the overloading.
What needs to be reminded is that,take reference operator,如 & &mut 等,是不允许重载的.因此,取引用& 和 解引用* not symmetrical complementarity.*&T的类型一定是T,而&*T is not necessarily the type of T.
更重要的是,读者需要理解,在某些情况下,Help us to insert the automatic compiler deref 的调用,简化代码.
边栏推荐
猜你喜欢
一本通2074:【21CSPJ普及组】分糖果(candy)
从源码方面来分析Fragment管理中 Add() 方法
[Implementation of the interface for adding, deleting, checking, and modifying a double-linked list]
Five Star Holdings Wang Jianguo: Deepen the track with "plant spirit" and promote growth with "animal spirit"
【微服务~Nacos】Nacos之配置中心
你真的了解乐观锁和悲观锁吗?
STC8H开发(十五): GPIO驱动Ci24R1无线模块
任务流执行器是如何工作的?
This article lets you quickly understand implicit type conversion [integral promotion]!
Pagoda measurement - building LightPicture open source map bed system
随机推荐
Space not freed after TRUNCATE table
This article lets you quickly understand implicit type conversion [integral promotion]!
json case
APP自动化测试框架-UiAutomator2基础入门
论文解读(DropEdge)《DropEdge: Towards Deep Graph Convolutional Networks on Node Classification》
Bean life cycle
好未来,想成为第二个新东方
AI识万物:从0搭建和部署手语识别系统
L3-2 Delete up to three characters (30 points)
The overall construction process of the Tensorflow model
宝塔实测-搭建LightPicture开源图床系统
Converting angles to radians
数独 | 回溯-7
论文解读(DropEdge)《DropEdge: Towards Deep Graph Convolutional Networks on Node Classification》
深度剖析 Apache EventMesh 云原生分布式事件驱动架构
Simple questions peek into mathematics
Cookie、session、token
In-depth analysis of Apache EventMesh cloud-native distributed event-driven architecture
Five Star Holdings Wang Jianguo: Deepen the track with "plant spirit" and promote growth with "animal spirit"
金山云地震,震源在字节?