Is it possible to have a function with a generic argument that converts that argument to an Arc
with a generic trait? Something like this:
struct Foo<TypeOrTrait> {
arc: Option<Arc<TypeOrTrait>>,
}
impl<TypeOrTrait> Foo<TypeOrTrait> {
fn set<T>(&mut self, t: T) -> Arc<T> {
let arc = Arc::new(t);
self.arc = Some(arc.clone()); // Error
arc
}
}
The code complains that it can't convert Arc<T>
to Arc<TypeOrTrait>
.
In my code I don't have just the Arc
that wraps TypeOrTrait
, but a complex Arc<RwLock<Inner<TypeOrTrait>>>
so I can't work around this by passing Arc<TypeOrTrait>
to the set
function.
The use case I have is that I want to have a collection that only implements a trait, but also want to have a way to access/modify the values using their original types. Something like this:
let foo: Foo<fmt::Display> = Foo { arc: None };
let value = foo.set(1u8);
assert_eq!(*value, 1u8);
assert_eq!(foo.bar.unwrap().to_string(), "1");
let value = foo.set(2u16);
assert_eq!(*value, 2u16);
assert_eq!(foo.bar.unwrap().to_string(), "2");
I was told that this would require higher kinded types, is that correct? If so, could it be emulated with something like what they do here (my Rust fu isn't on a par with that)?
CodePudding user response:
If you have only few traits and types, you can use a custom trait:
pub trait ConvertArc<To: ?Sized> {
fn convert(self: Arc<Self>) -> Arc<To>;
}
impl<T: ?Sized> ConvertArc<T> for T {
fn convert(self: Arc<Self>) -> Arc<Self> { self }
}
impl ConvertArc<dyn Trait> for Struct {
fn convert(self: Arc<Self>) -> Arc<dyn Trait> { self }
}
struct S<TypeOrTrait: ?Sized> {
arc: Option<Arc<TypeOrTrait>>,
}
impl<TypeOrTrait: ?Sized> S<TypeOrTrait> {
fn set<T: ConvertArc<TypeOrTrait>>(&mut self, t: T) -> Arc<T> {
let arc = Arc::new(t);
self.arc = Some(arc.clone().convert());
arc
}
}
If you have many traits or types... well... I think you don't have a solution. You can almost use std::marker::Unsize
on nightly, but not, because you want to be able to use the same type for both too.