Trait 方法可以实现返回引用或拥有的值

2024-04-26

我正在尝试使用可以实现返回引用或拥有值的方法来定义特征。

就像是:

struct Type;
trait Trait {
    type Value;
    fn f(&self) -> Self::Value;
}
impl Trait for () {
    type Value = Type;
    fn f(&self) -> Self::Value {
        Type
    }
}
impl Trait for (Type,) {
    type Value = &Type; // error[E0106]: missing lifetime specifier
    fn f(&self) -> Self::Value {
        &self.0
    }
}

这段代码不起作用,因为&Type缺少生命周期说明符。我想要&Type拥有相同的寿命&self (i.e. fn f<'a>(&'a self) -> &'a Type),但我不知道如何用 Rust 表达这一点。

我设法找到了几种方法来使这段代码工作,但我不喜欢其中任何一个:

  1. 为特征本身添加显式生命周期:

    trait Trait<'a> {
        type Value;
        fn f<'b>(&'b self) -> Self::Value where 'b: 'a;
    }
    impl<'a> Trait<'a> for () {
        type Value = Type;
        fn f<'b>(&'b self) -> Self::Value
            where 'b: 'a
        {
            Type
        }
    }
    impl<'a> Trait<'a> for (Type,) {
        type Value = &'a Type;
        fn f<'b>(&'b self) -> Self::Value
            where 'b: 'a
        {
            &self.0
        }
    }
    

    我不喜欢这个解决方案的是任何使用Trait需要一个明确的生命周期(我认为这本质上不是必需的),而且该特性似乎实现起来不必要地复杂。

  2. 返回可能是也可能不是参考的东西 - 比如std::borrow::Cow https://doc.rust-lang.org/std/borrow/enum.Cow.html:

    trait Trait {
        type Value;
        fn f<'a>(&'a self) -> Cow<'a, Self::Value>;
    }
    impl Trait for () {
        type Value = Type;
        fn f<'a>(&'a self) -> Cow<'a, Self::Value> {
            Cow::Owned(Type)
        }
    }
    impl Trait for (Type,) {
        type Value = Type;
        fn f<'a>(&'a self) -> Cow<'a, Self::Value> {
            Cow::Borrowed(&self.0)
        }
    }
    

    我不喜欢这个解决方案的是().f() is a Cow<_>: 我需要打电话().f().into_owned()获得我的Type。这似乎是不必要的(并且在使用时可能会导致一些可以忽略不计的运行时开销Trait作为特征对象)。

    Also note that Cow is not good since it requires that Self::Value implements ToOwned https://doc.rust-lang.org/std/borrow/trait.ToOwned.html (thus, practically, Clone https://doc.rust-lang.org/std/clone/trait.Clone.html), which is too strong of a requirement. It's anyways easy to implement an alternative to Cow without such constraints.

这个问题还有其他解决方案吗?标准/最常见/首选是什么?


这可以通过使用额外的关联对象来选择是返回类型还是引用以及一些元编程魔法来解决。

首先,一些助手类型:

struct Value;
struct Reference;

trait ReturnKind<'a, T: ?Sized + 'a> {
    type Type: ?Sized;
}
impl<'a, T: ?Sized + 'a> ReturnKind<'a, T> for Value {
    type Type = T;
}
impl<'a, T: ?Sized + 'a> ReturnKind<'a, T> for Reference {
    type Type = &'a T;
}

ReturnKind是一个“类型级函数”,它返回T当“输入”是Value, and &T for Reference.

然后是特质:

trait Trait {
    type Value;
    type Return: for<'a> ReturnKind<'a, Self::Value>;

    fn f<'a>(&'a self) -> <Self::Return as ReturnKind<'a, Self::Value>>::Type;
}

我们通过“调用”类型级函数来生成返回类型ReturnKind.

“输入参数”Return需要实现该特征以允许我们编写<Return as ReturnKind<'a, Value>>。虽然我们不知道一生中的自我到底是什么,但我们可以让Return以......为界all可能的终生使用HRTB https://doc.rust-lang.org/nomicon/hrtb.html Return: for<'a> ReturnKind<'a, Value>.

Usage:

impl Trait for () {
    type Value = f64;
    type Return = Value;

    fn f(&self) -> f64 {
        42.0
    }
}

impl Trait for (f64,) {
    type Value = f64;
    type Return = Reference;

    fn f(&self) -> &f64 {
        &self.0
    }
}

fn main() {
    let a: (f64,) = ( ().f(), );
    let b: &f64 = a.f();
    println!("{:?} {:?}", a, b);
    // (42,) 42
}

请注意,上述仅在以下情况下有效Value类型有'static寿命。如果Value其本身的寿命是有限的,这个寿命必须被Trait。自从生锈尚不支持关联的生命周期 https://github.com/rust-lang/rfcs/blob/master/text/0195-associated-items.md#staging,它必须像这样使用Trait<'foo>, 很遗憾:

struct Value;
struct Reference;
struct ExternalReference;

trait ReturnKind<'a, 's, T: ?Sized + 'a + 's> {
    type Type: ?Sized;
}
impl<'a, 's, T: ?Sized + 'a + 's> ReturnKind<'a, 's, T> for Value {
    type Type = T;
}
impl<'a, 's, T: ?Sized + 'a + 's> ReturnKind<'a, 's, T> for Reference {
    type Type = &'a T;
}
impl<'a, 's, T: ?Sized + 'a + 's> ReturnKind<'a, 's, T> for ExternalReference {
    type Type = &'s T;
}

trait Trait<'s> {
    type Value: 's;
    type Return: for<'a> ReturnKind<'a, 's, Self::Value>;

    fn f<'a>(&'a self) -> <Self::Return as ReturnKind<'a, 's, Self::Value>>::Type;
}

impl Trait<'static> for () {
    type Value = f64;
    type Return = Value;

    fn f(&self) -> f64 {
        42.0
    }
}

impl Trait<'static> for (f64,) {
    type Value = f64;
    type Return = Reference;

    fn f(&self) -> &f64 {
        &self.0
    }
}

impl<'a> Trait<'a> for (&'a f64,) {
    type Value = f64;
    type Return = ExternalReference;

    fn f(&self) -> &'a f64 {
        self.0
    }

}

fn main() {
    let a: (f64,) = ( ().f(), );
    let b: &f64 = a.f();
    let c: &f64 = (b,).f();
    println!("{:?} {:?} {:?}", a, b, c);
    // (42,) 42 42
}

但如果特征上有生命周期参数就可以了,那么OP已经提供了一个更简单的解决方案:

trait Trait<'a> {
    type Value;
    fn f<'b>(&'b self) -> Self::Value where 'b: 'a;
}

impl<'a> Trait<'a> for () {
    type Value = f64;
    fn f<'b: 'a>(&'b self) -> Self::Value {
        42.0
    }
}

impl<'a> Trait<'a> for (f64,) {
    type Value = &'a f64;
    fn f<'b: 'a>(&'b self) -> Self::Value {
        &self.0
    }
}
impl<'a, 's> Trait<'s> for (&'a f64,) {
    type Value = &'a f64;
    fn f<'b: 's>(&'b self) -> Self::Value {
        self.0
    }
}

fn main() {
    let a: (f64,) = ( ().f(), );
    let b: &f64 = a.f();
    let c: &f64 = (b,).f();
    println!("{:?} {:?} {:?}", a, b, c);
    // (42,) 42 42
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Trait 方法可以实现返回引用或拥有的值 的相关文章

随机推荐

  • React Router - 如何确定是否按下了后退按钮?

    我有这些场景 设置页面 gt 结果页面 gt 详细信息页面 用户选择设置 单击下一步 获取结果 然后单击查看更多详细信息 详情页 gt 结果页 用户从详细信息页面返回结果页面 这会导致完全重新渲染 导致我毫无意义地再次访问服务器 我将结果存
  • 动态更改 Dropzone url

    我正在尝试更改 dropzone 中的 URL 但我发现的信息似乎对我不起作用 我有一个表单 我正在使用 JS 放置一个拖放区 我想根据下拉列表中选择的选项来更改 dropzone URL 这是我正在使用的代码 Dropzone
  • 将 Hibernate linq 查询转换为 HQL

    我知道 IQueryable 无法序列化 这意味着查询无法序列化 发送到 Web 服务 反序列化 查询然后发回 我想知道是否可以将 hibernate linq 查询转换为 hql 以通过网络发送 我还缺少另一条路线吗 我想我已经看到 AD
  • 如何设置 PrimeFaces 主题?

    我正在尝试让我的 PrimeFaces v2 1 应用程序使用不同的主题 我下载了 vader 1 0 0 jar 并将其放在我的 WEB INF lib 文件夹中 我将以下内容添加到我的 web xml 中
  • 用 Python 绘制生成器的数据

    Python IPython Jupyter笔记本 中是否有任何接受的绘图选项发电机 AFAIK matplotlib不支持这一点 我发现的唯一选择是plot ly http plot ly使用他们的 Streaming API 但我不想使
  • 如何在 OpenCV 中更好地计算射线线段交点?并得到它的交点和距原点的距离?

    我有 4 条线段 A B C 和 D 每条线都表示为两个点 例如 线A由点A1和点A2表示 我想要的是 点 X 即线 A 射线与线 B 相交的点 X与A1 原点 之间的距离 测试相交时 线 A 射线不应 与线段 D 相交 与线段C相交 我该
  • 如何在 Swift 中将 CMutablePointer 设置为 false?

    基本上我在 Swift 中使用 AssetsLibrary 框架 如何将停止指针的值修改为 NO False 0 我什至不知道它应该除外什么值 self library enumerateGroupsWithTypes ALAssetsGr
  • 如何在 css 中对重新定位的 div 进行 z 索引

    Context 我正在尝试制作明显集中的菜单项 当鼠标悬停时改变颜色并扩大尺寸 虽然设置另一种颜色很容易 但尝试将其横向移动是一项比我想象的更复杂的任务 运动本身按其应有的方式工作 但项目的 z 索引变得混乱 Issue 背景颜色已按其应有
  • Cookie - 跨多个域设置

    我公司的设置如下 子域 1 域 1 子域名2 域名1 com 子域名3 域名1 com 子域名4 域名1 com 子域名5 域名1 com 子域名6 域名1 com 子域 1 域 2 子域 2 域 2 subdomain3 domain2
  • 是否可以为自定义组件(而不是 FormControl)创建一个验证器

    我正在尝试这样做 Directive selector myVal myCustomInputToComponent providers provide NG VALIDATORS useExisting forwardRef gt MyV
  • Windows 7 跳转列表(Windows 窗体、C#)

    有谁知道如何在 C 中自定义与我自己的应用程序相关的 Windows 跳转列表功能 我知道可以做到 但我在 MSDN 上找不到任何与 C Windows7 相关的内容 到目前为止 我能找到的与 W7 和 C 相关的唯一信息只是我已经阅读过的
  • 使用一个或多个标准 FIFO 队列实现延迟队列 [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 延迟队列是一种队列 其中每条消息都有
  • 二维数组,在 C 中使用 calloc

    我正在尝试创建一个二维字符数组来存储字符行 例如 lines 0 Hello lines 1 Your Back lines 2 Bye 由于行必须是动态的 因为我一开始不知道需要多少行 这是我的代码 int i char lines ch
  • Android:多个活动和手动切换视图哪个更好?

    我已经开发了一些 Android 应用程序 但这个问题始终存在 我应该如何构建我的用户界面 我应该在活动之后启动活动并让手机按下 后退 按钮 还是应该选择更优化但实现起来更复杂的方式手动切换视图 然后手动执行 后退 按钮功能 您认为 或知道
  • 如何在几年前拟合的逻辑回归中使用 R 中的预测函数?

    我有一个问题正在尝试解决 但没有成功 寻找了两天多 却没有得到任何线索 很抱歉 如果答案就在那里 但我没有找到 假设您有一个来自几年前估计的旧模型的逻辑方程回归 二元模型 因此 您知道参数 k k 1 2 p 因为它们是过去估计的 但您没有
  • MySQL 错误:#1142 - SELECT 命令被拒绝给用户

    我在一台服务器上的某个查询时遇到问题 在我测试过的所有其他地方 它工作得很好 但在我想使用它的服务器上 它不起作用 这是关于以下 SQL SELECT facturen id AS fid projecten id AS pid titel
  • 跨命名空间共享秘密

    有没有办法在 Kubernetes 中跨命名空间共享秘密 我的用例是 我的所有命名空间都有相同的私有注册表 并且我想避免为每个命名空间创建相同的秘密 秘密 API 对象驻留在命名空间中 它们只能由同一命名空间中的 pod 引用 基本上 您必
  • 限制在指定时间访问互联网

    我正在尝试做一个家长控制软件项目 我阻止了特定网站并使用主机文件取消阻止它们 后来 我尝试通过以编程方式禁用和启用 LAN 连接来禁用 启用互联网访问 C 有没有办法在特定时间阻止互联网访问 例如8 January 2013之间20 00
  • USB 端口速度 Linux [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 如何以编程方式确定运行 Linux 内核的嵌入式设备中的 USB 端口速度 你可以阅读 sys bus usb devices usb s
  • Trait 方法可以实现返回引用或拥有的值

    我正在尝试使用可以实现返回引用或拥有值的方法来定义特征 就像是 struct Type trait Trait type Value fn f self gt Self Value impl Trait for type Value Typ