I am using a crate which has a struct (lets call it ChosenContainer ) that I want to use. I want to store a ChosenContainer in my OwnContainer struct. But I am not sure what the type of the stored value should be.
I made a small code snippet which corresponds to my situation. I tried all different types in my OwnContainer.
I tried Boxing the ChosenContainer struct: c_container: Box<ChosenContainer<dyn Chosen>>
I tried trait bounds c_container: ChosenContainer<T> where T: Chosen
I tried combining them.
Googled for a few hours.
I have no idea how to do this. Is this even possible?
// --- code from a foreign crate simplified below --- //
pub struct Thing;
pub trait Chosen {}
impl Chosen for Thing {}
pub fn get_chosen() -> impl Chosen {
Thing
}
pub struct ChosenContainer<C: Chosen> {
chosen: C,
}
impl<C: Chosen> ChosenContainer<C> {
pub fn new(chosen: C) -> Self {
ChosenContainer { chosen }
}
}
// --- my code so we can edit stuff below --- //
// should own a ChosenContainer
struct OwnContainer {
c_container: ChosenContainer<dyn Chosen>,
}
impl OwnContainer {
fn new() -> Self { // I want to keep function signiture
let c = get_chosen();
let c_container = ChosenContainer::new(c);
OwnContainer {
c_container,
}
}
}
fn main() {
// should be able to create one like this:
let own_container = OwnContainer::new();
}
The two road bumps here appear to be that you can't name opaque types such as the one returned from get_chosen(), and that Box<dyn Trait> doesn't implement Trait. You can work around the second one using a new type, assuming you're able to impl Chosen. Here's a sketch based off your example on the playground.
As @quinedot pointed out the compiler nicely tells me that "implementing a foreign trait is only possible if at least one of the types for which is it implemented is local"
This also works, but it’s a bit weird and attaches a type parameter to OwnContainer:
// should own a ChosenContainer
struct OwnContainer<C:Chosen> {
c_container: ChosenContainer<C>,
}
// `Thing` is any arbitrary type that implements `Chosen`;
// It’s only here to make type inference work nicely.
impl OwnContainer<Thing> {
fn new() -> OwnContainer<impl Chosen> {
// I want to keep function signiture
let chosen = get_chosen();
let c_container = ChosenContainer::new( chosen );
OwnContainer { c_container }
}
}
fn main() {
// should be able to create one like this:
let own_container = OwnContainer::new();
}
On nightly, we have the type_alias_impl_trait feature which makes this a bit nicer: we can define a default inner type that lets us skip the type parameter and we can use that alias in our impl block:
#![feature(type_alias_impl_trait)]
type DefaultChosen = impl Chosen;
// should own a ChosenContainer
struct OwnContainer<C:Chosen = DefaultChosen> {
c_container: ChosenContainer<C>,
}
impl OwnContainer<DefaultChosen> {
fn new() -> Self {
// I want to keep function signiture
let chosen = get_chosen();
let c_container = ChosenContainer::new( chosen );
OwnContainer { c_container }
}
}
fn main() {
// should be able to create one like this:
let own_container = OwnContainer::new();
}