Rust的ToOwned特征:泛型版的Clone
std::borrow::ToOwned是Rust标准库中的一个特征,用于从借用的数据中创建一个具有所有权的副本。它的作用和Clone是一样的,但是相比Clone,它支持泛型;也就是说我们可以将一个类型T“Clone”为另一个类型U。这对处理一些特殊的类型来说很有用。ToOwned的签名
ToOwned提供了两个方法,其中一个是必须实现的:
pub trait ToOwned {
type Owned: Borrow<Self>;
// Required method
fn to_owned(&self) -> Self::Owned;
// Provided method
fn clone_into(&self, target: &mut Self::Owned) { ... }
}例子
说到例子,就不得不再次请出我文章里的常客——str和。众所周知,因为str和是切片类型,它们在编译时大小未知,因此Rust无法在栈上为它们分配空间;这就导致了我们几乎不会直接持有str和变量:
fn main() {
let foo: str;
let bar: ;
}这段代码会被编译器直接报错:
https://img2024.cnblogs.com/blog/1519438/202402/1519438-20240228123406707-458039744.png
str和是不能被持有了,但是Clone它们的需求是确实存在的;因此,Rust就提供了将这些切片类型“Clone”为栈上类型的方案:ToOwned。打开标准库文档和源码,我们可以看到str这样实现了ToOwned:
#
impl ToOwned for str {
type Owned = String;
#
fn to_owned(&self) -> String {
unsafe { String::from_utf8_unchecked(self.as_bytes().to_owned()) }
}
fn clone_into(&self, target: &mut String) {
let mut b = mem::take(target).into_bytes();
self.as_bytes().clone_into(&mut b);
*target = unsafe { String::from_utf8_unchecked(b) }
}
}也可以看到这样实现了ToOwned:
#
impl<T: Clone> ToOwned for {
type Owned = Vec<T>;
#
fn to_owned(&self) -> Vec<T> {
self.to_vec()
}
#
fn to_owned(&self) -> Vec<T> {
hack::to_vec(self, Global)
}
fn clone_into(&self, target: &mut Vec<T>) {
SpecCloneIntoVec::clone_into(self, target);
}
}于是,用户虽然不能直接Clonestr和,但却可以把它们用ToOwned“Clone”为String和Vec。
小插曲:在日常开发中,我们经常使用的方法String::from(&str),其实现正是依赖于str的to_owned特征:
#
impl From<&str> for String {
#
fn from(s: &str) -> String {
s.to_owned()
}
}总结
对普通的开发者来说,对ToOwned有一些了解就已经完全足够了;而对API的设计者来说,巧用ToOwned可以让你的类型在一些特殊情况下更灵活、更高效。
下篇文章介绍的是Rust中经常被人忽视的智能指针Cow,我之前在学习Rust时就注意到无论是the book,还是Rust圣经,都没有讲到Cow,希望我的工作能为Rust增加一点可供新人参考的资料。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页:
[1]