Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement a trait when one of the associated types is impossible to name?

I have a function that returns an impl Trait so I don't have access to the concrete return type. I need to use the return value of that function as an associated type in a trait. How do I do that?

Here is a simplified example:

fn f() -> impl Iterator<Item = u8> {
    std::iter::empty()
}

struct S;

impl IntoIterator for S {
    type Item = u8;
    type IntoIter = (); // What can I write here ?

    fn into_iter(self) -> Self::IntoIter {
        f()
    }
}

Is it even possible to do (without resorting to boxing the iterator)?

like image 919
lovasoa Avatar asked Apr 16 '19 15:04

lovasoa


1 Answers

Unfortunately, you can't. At least not yet.

There is an RFC, Named existentials and impl Trait variable declarations (tracking issue), which would allow you to declare a public type name at the module level, whose type definition is inferred from how it used within the module. Users of the module can refer to this type by its public name and it can be used as an associated type.

It's difficult to guess when a new feature will stabilise and in the meantime there really aren't many good options. Aside from things that might only work because of specifics of your use-case, the general workaround is to use a trait object:

impl IntoIterator for S {
    type Item = u8;
    type IntoIter = Box<dyn Iterator<Item = u8>>;

    fn into_iter(self) -> Self::IntoIter {
        Box::new(f())
    }
}

If it is acceptable to use nightly features, you can help test out the RFC before it stabilises:

#![feature(existential_type)]

impl IntoIterator for S {
    type Item = u8;
    existential type IntoIter: Iterator<Item = u8>;

    fn into_iter(self) -> Self::IntoIter {
        f()
    }
}
like image 141
Peter Hall Avatar answered Nov 14 '22 04:11

Peter Hall