【问题标题】:Is it possible to create a generic impl for a trait that works with all but one subset of types?是否可以为除一个类型子集以外的所有类型工作的特征创建通用 impl?
【发布时间】:2020-02-17 18:46:01
【问题描述】:

我正在尝试编写一个通用方法,该方法接受一个返回Serialize 值或Arc<Serialize> 值的函数。我的解决方案是创建一个特征以在需要时解开 Arc 并生成对基础值的引用:

use serde::Serialize;
use std::sync::Arc;

pub trait Unwrapper {
    type Inner: Serialize;

    fn unwrap(&self) -> &Self::Inner;
}

impl<T> Unwrapper for T
where
    T: Serialize,
{
    type Inner = T;
    fn unwrap(&self) -> &Self::Inner {
        self
    }
}

impl<T> Unwrapper for Arc<T>
where
    T: Serialize,
{
    type Inner = T;
    fn unwrap(&self) -> &Self::Inner {
        self
    }
}

fn use_processor<F, O>(processor: F)
where
    O: Unwrapper,
    F: Fn() -> O,
{
    // do something useful processor
}

我收到 E0119 错误,因为 Arc 将来可能会实现 Serialize,就像我启用 serde crate 的功能以允许这样做:

error[E0119]: conflicting implementations of trait `Unwrapper` for type `std::sync::Arc<_>`:
  --> src/lib.rs:20:1
   |
10 | / impl<T> Unwrapper for T
11 | | where
12 | |     T: Serialize,
13 | | {
...  |
17 | |     }
18 | | }
   | |_- first implementation here
19 | 
20 | / impl<T> Unwrapper for Arc<T>
21 | | where
22 | |     T: Serialize,
23 | | {
...  |
27 | |     }
28 | | }
   | |_^ conflicting implementation for `std::sync::Arc<_>`

我不想这样做,因为我只想在顶层允许Arc,而不是在值内(出于同样的原因,该功能默认情况下不启用)。鉴于此,有没有办法只为Arc 禁用我的第一个impl?还是有更好的解决问题的方法?

【问题讨论】:

标签: generics rust traits


【解决方案1】:

您的尝试没有成功,因为 不可能有重叠的特征实现。

下面尝试编写一个接受Serialize 值或 ArcSerialize 值。

它利用 Borrow 特征及其对任何 T 的全面实现。

注意在泛型方法的调用站点上使用 turbo fish 语法。

use std::sync::Arc;
use std::borrow::Borrow;
use serde::Serialize;

#[derive(Serialize, Debug)]
struct Point {
    x: i32,
    y: i32,
}

fn myserialize<T: Borrow<I>, I: Serialize>(value: T) {
    let value = value.borrow();
    let serialized = serde_json::to_string(value).unwrap();
    println!("serialized = {}", serialized);
}


fn main() {
    let point = Point { x: 1, y: 2 };
    myserialize(point);

    let arc_point = Arc::new(Point { x: 1, y: 2 });
    myserialize::<_, Point>(arc_point);

}

【讨论】:

  • 谢谢,我意识到我错过了问题的一个方面。有没有办法总结 T: Borrow&lt;I&gt;, I: Serialize 来描述像 Fn() -&gt; ??? 这样的函数的返回值,我将更新我的问题以包含该附加细节。
  • 试试签名fn use_processor&lt;F, O, I&gt;(processor: F) where O: Borrow&lt;I&gt;, I: Serialize, F: Fn() -&gt; O {}
  • 谢谢,成功了。使用涡轮鱼的要求很烦人,因为我有 6 个类型参数(所以调用中有一堆额外的_s),但我可以忍受。如果我相信如果专业化落地我的原始方法会奏效,我是否正确?
  • 我已经尝试了具有专业化功能的最新版本的代码,但我无法使其正常工作:请参阅 here
  • 我希望这会起作用,因为在我看来 TInner 是同一类型(即某种类型是 Serialize)似乎很明显。也许这是当前专业化实现的限制。
猜你喜欢
  • 2016-10-18
  • 2017-01-21
  • 2022-10-02
  • 1970-01-01
  • 2021-07-22
  • 1970-01-01
  • 1970-01-01
  • 2022-09-24
相关资源
最近更新 更多