为用户定义类型实现 ToOwned

2024-03-18

考虑以下示例代码:

#[derive(Clone)]
struct DataRef<'a> {
    text: &'a str,
}

#[derive(Clone)]
struct DataOwned {
    text: String,
}

我要实施ToOwned for DataRef这样:

impl ToOwned for DataRef<'_> {
    type Owned = DataOwned;

    fn to_owned(&self) -> DataOwned {
        DataOwned {
            text: self.text.to_owned(),
        }
    }
}

从字面上看,这句话有道理吧?但也存在一些问题。


第一个问题是,因为ToOwned提供了一个一揽子实施 https://doc.rust-lang.org/std/borrow/trait.ToOwned.html#implementors:

impl<T> ToOwned for T where T: Clone { ... }

上面的代码会出现编译错误:

error[E0119]: conflicting implementations of trait `std::borrow::ToOwned` for type `DataRef<'_>`
  --> src/main.rs:13:1
   |
13 | impl ToOwned for DataRef<'_> {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: conflicting implementation in crate `alloc`:
           - impl<T> ToOwned for T
             where T: Clone;

好吧,我们可以做出一些妥协。让我们删除#[derive(Clone)] from DataRef。 (但是,在我的实际情况中我不能这样做,因为这是一个破坏性的改变并且没有意义)


然后是第二个问题,关联类型Owned of ToOwned requires https://doc.rust-lang.org/std/borrow/trait.ToOwned.html它实现了Borrow<Self> https://doc.rust-lang.org/std/borrow/trait.Borrow.html.

pub trait ToOwned {
    type Owned: Borrow<Self>;

    fn to_owned(&self) -> Self::Owned;

    ...
}

如果我们实施Borrow for DataOwned正如其定义:

impl<'a> Borrow<DataRef<'a>> for DataOwned {
    fn borrow(&self) -> &DataRef<'a> {
        DataRef { text: &self.text }
    }
}

这显然是不可能的,因为我们无法存储DataRef某处。


所以我的问题是:

  • 有什么办法可以实现ToOwned对于上面的例子?

  • 考虑上面的问题,就是ToOwned不应该由用户手动实现吗?因为我无法想象一个真实的例子来反对这一点。

  • (可选答案)如果更改 std 的定义ToOwned是允许的,是否有任何可能的改进可以使其变得更好? (允许不稳定和未实现的 Rust 功能)


您看到的问题是因为ToOwned不应该被实施对于参考类型但对于一个参照物。注意什么标准库的实现 https://doc.rust-lang.org/std/borrow/trait.ToOwned.html#implementors看起来像:

impl ToOwned for str
impl ToOwned for CStr
impl ToOwned for OsStr
impl ToOwned for Path
impl<T> ToOwned for [T]

这些都是!Sized, !Clone总是出现在某些通用指针类型内部的类型(例如&str, Box<str>, &Path) 或专门拥有的指针类型 (String包含一个str; PathBuf包含一个Path; Vec<T>包含一个[T])。的目的ToOwned是允许从参考数据——不是你所说的东西FooRef但实际的&— 到专门拥有的指针类型,以这样的方式进行转换:可逆且一致(这就是Borrow<Self>是关于)。

如果您想获得以下好处Borrow and ToOwned,您需要定义一个不是引用但引用可以指向的类型,如下所示:

use std::borrow::Borrow;
#[repr(transparent)]
struct Data {
    text: str,
}

#[derive(Clone)]
struct DataOwned {
    text: String,
}

impl Borrow<Data> for DataOwned {
    fn borrow<'s>(&'s self) -> &'s Data {
        // Use unsafe code to change type of referent.
        // Safety: `Data` is a `repr(transparent)` wrapper around `str`.
        let ptr = &*self.text as *const str as *const Data;
        unsafe { &*ptr }
    }
}

impl ToOwned for Data {
    type Owned = DataOwned;
    fn to_owned(&self) -> DataOwned {
        DataOwned { text: String::from(&self.text) }
    }
}

但请注意,该策略only适用于单个连续数据块(例如文件中的 UTF-8 字节)str)。没有办法实现Borrow + ToOwned以一种适用于DataOwned其中包含two字符串。 (这可以针对一个字符串和一些固定大小的数据完成,但这仍然具有挑战性,因为 Rust 尚未很好地支持自定义动态大小的类型。)

为了一个人做这一切通常并不值得String包装器,但如果您想对内容强制执行一些更强的类型/有效性不变性(例如“所有字符都是 ASCII”或“字符串(或字符串切片)是格式良好的 JSON 片段”),那么它可能是值得的,and您希望能够与期望的现有通用代码进行交互ToOwned将要执行。

如果您只是想能够调用.to_owned()上的方法DataRef,不用理会ToOwned特征;只需编写一个固有(非特征)方法即可。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为用户定义类型实现 ToOwned 的相关文章

随机推荐

  • 如何使用 WinRT 获取文件?

    我想要的是 从 AppData 获取要使用的 xml 我编码的内容 StorageFolder localFolder Windows Storage ApplicationData Current LocalFolder StorageF
  • 使用 R 在一张图中绘制光谱数据

    我有多个数据框 其中第一列 最后填充 NA 是波数 其他列是多次观测的特定波数的变量 是否有可能以我的第一列保存 x 轴变量而另一列绘制为具有各自 y 值的大图的方式绘制列 我已经尝试过 matplot 结果是 数字 而不是点 matplo
  • Microsoft Graph 和 Azure Ad 用户身份验证

    我在 Azure 广告中注册了一个应用程序 当我使用以下详细信息执行 ADAL 时 我会获得一个授权令牌以与 microsoft graph api 一起使用 username email protected cdn cgi l email
  • 如何在 Laravel 5.2 中以 JSON 格式返回 403 响应?

    我正在尝试使用 Laravel 5 2 开发 RESTful API 我偶然发现如何以 JSON 格式返回失败的授权 目前 它抛出 403 页面错误而不是 JSON 控制器 TenantController php class Tenant
  • 与 fork() 共享堆内存

    我正在努力用 C 语言实现一个数据库服务器 它将处理来自多个客户端的请求 我在用fork 处理单个客户端的连接 服务器将数据存储在堆中 堆由指向动态分配记录的哈希表的根指针组成 记录是具有指向各种数据类型的指针的结构 我希望进程能够共享这些
  • 使用 Pyside + Python 中的类进行样式设计

    如何使用类更好地设计该应用程序的样式 而不是为每个看起来相同的标签重新定义相同的样式 更改样式变得很痛苦 因为我必须仔细检查每个看起来相同的标签并粘贴代码以进行匹配 usr bin python coding utf 8 import sy
  • Cordova CLI,使用 Git,并保存插件/平台

    我正在尝试找出如何将一些 Cordova git 最佳实践 与我认为的现实相协调 我希望有人能为我阐明这一点 如果我理解正确的话 当前的 最佳实践 是将这些目录添加到我的 gitignore 来自 使用 Cordova CLI 进行开发 一
  • 有人可以解释一下 xml:base 属性在 XHTML5 中的用途吗?

    我想知道 xml base 属性的作用是什么以及它在 XHTML5 中的值是什么 xml base 属性有什么限制吗 文档为xml base可以被找寻到here http www w3 org TR xmlbase syntax 它允许重新
  • 在 Java 中将列表迭代器传递给多个线程

    我有一个包含大约 200K 元素的列表 我是否能够将此列表的迭代器传递给多个线程 并让它们迭代整个列表 而没有任何一个线程访问相同的元素 这就是我此刻的想法 Main public static void main String args
  • Statsmodels Poisson glm 与 R 不同

    我正在尝试根据 R 中提供的一些代码来拟合一些模型 空间交互模型 我已经能够在 python 框架中使用 statsmodels 使一些代码正常工作 但其中一些代码根本不匹配 我相信我的 R 和 Python 代码应该给出相同的结果 有人看
  • 非模板化成员函数的enable_if用法[重复]

    这个问题在这里已经有答案了 C 程序设计语言 第四版 一书 第28 4章 第796页 解释了enable if并给出了使operator gt 成为条件定义的示例 书中的例子只是一个代码片段 我将其完成为程序如下 include
  • lua __pairs 的实际实现是什么?

    有谁知道 lua 5 2 的实际实现吗 元方法 pairs 换句话说 我如何实施 pairs作为元表中的元方法 因此它的工作原理与pairs 我需要覆盖 pairs并想跳过我在表中添加的一些虚拟变量 下面将使用元表元来显式提供pairs默认
  • 更改数组适配器中列表项的文本颜色

    我创建一个列表视图并在自定义对话框中实现该列表视图 该列表视图使用数组适配器 在我的数组适配器中 我使用自己的布局和所需的颜色 代码如下 listView new ListView context ArrayAdapter
  • PHP Printf 作为浮点精度

    我正在尝试使用 PHPprintf功能打印出用户的存储容量 完整的公式看起来像这样 echo printf 02f size 1024 1024 GB 鉴于 size 10 1024 1024 这应该打印出来 10 00 GB 但事实并非如
  • 读取 byte[] 历史队列

    我正在尝试编写一个我知道数组大小的字节数组 但是我无法解析结果数据 我正在使用以下代码 okAppender writeBytes b gt b write byteData and byte byteData new byte 500 o
  • 如何在phpmyadmin中导入大型sql文件

    我想导入一个大约 12 mb 的 sql 文件 但它在加载时引起问题 有没有办法在不分割sql文件的情况下上传它 尝试根据您的操作系统的口味从 mysql 控制台导入它 mysql u DB USER NAME p DB NAME lt d
  • Spring Boot:禁用特定 URL 的客户端身份验证

    我的配置中有以下配置application yml server address port 8443 sessionTimeout 30 ssl client auth need key store keyStore jks key sto
  • Xamarin iOS 通用链接支持 Twitter 身份验证

    所以 现在 Twitter 从 9 月 25 日开始支持通用链接 这意味着当 UIWebView 命中时https twitter com oauth authorize oauth token https twitter com oaut
  • 仅根据字段名称对类数组进行排序

    我有一个应用程序 用户向我提供字段名称 例如name or costInCents 我必须按该字段排序 我有办法保证字段名称是正确的 这个应用程序导致了我根本无法上课的复杂情况Comparable并实施具体的compareTo 因为自定义实
  • 为用户定义类型实现 ToOwned

    考虑以下示例代码 derive Clone struct DataRef lt a gt text a str derive Clone struct DataOwned text String 我要实施ToOwned for DataRe