当前位置:网站首页>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 的调用,简化代码.
边栏推荐
- Tensorflow中使用convert_to_tensor去指定数据的类型
- JSON 基本使用
- Activiti7审批流
- Js fifteen interview questions (with answers)
- Cookie、session、token
- 【EF】数据表全部字段更新与部分字段更新
- This article lets you quickly understand implicit type conversion [integral promotion]!
- Metasploit常用命令、技术功能模块
- CVPR22 Oral | shunt through multi-scale token polymerization from attention, code is open source
- TF使用constant生成数据
猜你喜欢

Activiti7审批流

腾讯继续挥舞降本增效“大刀”,外包员工免费餐饮福利被砍了

TF generates uniformly distributed tensor
![[Implementation of the interface for adding, deleting, checking, and modifying a double-linked list]](/img/49/ebedcd4d27aa608360ac17e504f36d.png)
[Implementation of the interface for adding, deleting, checking, and modifying a double-linked list]

AI Knows Everything: Building and Deploying a Sign Language Recognition System from Zero

ACM MM 2022 | Cloud2Sketch: Painting with clouds in the sky, AI brush strokes

论文解读(DropEdge)《DropEdge: Towards Deep Graph Convolutional Networks on Node Classification》

POWER SOURCE ETA ETA Power Repair FHG24SX-U Overview

Metasploit常用命令、技术功能模块
Quotefancy ,提供鼓舞人心语录的壁纸网站 - 倾城之链
随机推荐
CVPR22 Oral|通过多尺度token聚合分流自注意力,代码已开源
数独 | 回溯-7
mysql multi-table left link query
ACM MM 2022 | Cloud2Sketch: 长空云作画,AI笔生花
Basic operations of openGauss database (super detailed)
腾讯继续挥舞降本增效“大刀”,外包员工免费餐饮福利被砍了
宝塔实测-搭建LightPicture开源图床系统
SQLi-LABS Page-2 (Adv Injections)
SecureCRT background color
unit test
Flutter 绘制美不胜收的光影流动效果
Multiple reasons for MySQL slow query
Liver all night to write a thirty thousand - word all the commands the SQL database, function, speaks clearly explain operators, content is rich, proposal collection + 3 even high praise!
一本通2074:【21CSPJ普及组】分糖果(candy)
编译原理之文法
AI+Medical: Using Neural Networks for Medical Image Recognition and Analysis
Use zeros(), ones(), fill() methods to generate data in TF
1215 – Cannot add foreign key constraint
Solution: Edu Codeforces 109 (div2)
金山云地震,震源在字节?