Closures in API design – theoretical limitations and best practices?

Interesting, I didn't know that. (Playground)

I suspect it's this impl in std:

impl<A, V> FromIterator<Option<A>> for Option<V>where
    V: FromIterator<A>,

This might come in handy in a couple of cases. Thanks for that hint.

I guess it only works though, because collect is very generic. So here, generics (in std) help to avoid friction.


Maybe the example was a bad one then. But I would still run into problems if I attempted to do anything async, right? (edit: see update below) And in case of Regex::replace_all, the problem of lack of fallibility does exist.

Perhaps I still have no good "feeling" in regard to when a closure/callback does cause problems, and when it doesn't.


Update:

Regarding .map and async, there remains the question of the ordering of realizing the futures. I guess that's what FuturesOrdered and FuturesUnordered are for. So it is possible to write the example functional style if you use these. It requires a bit of Option/Result gymnastics though, it seems:

use futures::stream::{FuturesOrdered, TryStreamExt};
use tokio::task::yield_now;

async fn functional_style() -> Option<Vec<u8>> {
    FuturesOrdered::from_iter((20u8..=25).map(|i| async move {
        yield_now().await;
        i.checked_mul(10).ok_or(())
    }))
    .try_collect()
    .await
    .ok()
}

(Playground)