金属Rust:Borrow
与AsRef
最近在调整Writium的结构,自己果然开始嫌弃Iron麻烦了。造*的灵魂觉醒了!那么在包裹Hyper的Request
和Response
的过程中,遇到了个问题:到底应该用什么取引用好呢?
在std
中我们能找到两个用于取引用的trait:Borrow
和AsRef
(以及对应的BorrowMut
和AsMut
)。还是挺容易混淆的,毕竟好像它们的意思都是取引用,“借”走一个对象。那么就先来看看文档是怎么说的。
Borrow
Borrow
在文档中的定义如下:
A trait for borrowing data.
简单来说就是告诉用户,从这个类型中能借走另一个类型。在下面的文段中又进一步进行了解释:
When writing generic code, it is often desirable to abstract over all ways of borrowing data from a given type. That is the role of the
Borrow
trait: ifT: Borrow<U>
, then&U
can be borrowed from&T
.
即,Borrow<Borrowed>
的类型都是Borrowed
的一个更大的概念。比如说,String
的结构中含有str
(意思到了就行),于是String
实现了Borrow<str>
,这样就知道String
是str
的一种变式了。
在泛型中,要求泛型参数实现Borrow<Borrowed>
所表达的意思是:我需要Borrowed
的一种引用形式(值本身、引用或是包裹类型)。自己应当直接或间接拥有这个Borrowed
类型的实例。 也就是说,&&T
是不可以实现Borrow<T>
的。
AsRef
AsRef
在文档中的定义如下:
A cheap reference-to-reference conversion. Used to convert a value to a reference value within generic code.
也就是说,AsRef
是为了快速取自身引用存在的,只要能够被引用为另一类型、或自身类型的类型都可以实现AsRef
。可以认为as_ref
进行的操作和下面的代码类似:
(&self).into::<&TargetType>()
在泛型中,要求泛型参数实现AsRef<T>
所表达的意思是:我需要一个能被转换为类型T
引用的类型。不关心这个T
类型的引用所指向的实例是不是自己的一部分。
到底该用什么?
其实我也不是很清楚,这两个trait的界线不是很明晰,下面是我个人的一些看法:
如果仔细看std
中两个trait在String
和str
的实现情况的话能够发现,Borrow
只由String
实现了;而AsRef
由String
和str
两者都实现了。也就是说,如果只是简单的引用转换,实现AsRef
就好;如果是返回自身一部分的引用,最好把这两个trait都实现了。
在设计容器类型的时候,使用Borrow
可以让容器方法接受键、值类型本身及其引用。参考HashMap
的get
方法实现。
如果要在方法里保存一个引用在结构体,可以使用AsRef
来获取这个引用。
参考
std::convert::AsRef - Rust
std::borrow::Borrow - Rust
Borrow and AsRef - The Rust Programming Language