是否有可能为除了一个类型子集之外的所有类型都可使用的特征创建通用的impl?

问题描述 投票:1回答:1

我正在尝试编写一个通用方法,该方法接受一个返回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位于顶层,而不是位于值之内(出于相同的原因,默认情况下该功能未启用)。鉴于此,有没有办法仅对impl禁用我的第一个Arc?还是有更好的方法来解决问题?

generics rust traits
1个回答
2
投票

您的尝试无效,因为不可能有重叠的特征实现。

如评论中指出,RFC 1120描述在这种情况下乍看之下应该起作用的specialization功能。

[尝试编写接受Serialize值或Arc值的Serialize

它利用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);

}
© www.soinside.com 2019 - 2024. All rights reserved.