I’m curious about the conditions under which one would even take an iterator expecting one element… What problem are we solving where we’re trying to create an iterator with one item and then throwing the iterator away by pulling the item out? Why not just create the item without any iterator?
One might not be in control of the value source. It could be a stream, for example. There might also be multiple values involved in the whole process, but it ends with "and then get exactly one more item" for it to be correct.
I don't think I've personally come across enough usage for it to be a bother to not have it inside std. When I come across the situations I usually want some more custom behavior, so writing the "check the rest of the iterator" part isn't much of a burden.
However, if I were to use a std provided version, I'd probably prefer it to return a Result with an error value that provides me with a new iterator that I can use to inspect the wrong set of values for error reporting or fallbacks and such.
and have IteratorSingleErrorIterator (I know, awful name) contain the first item, next item, and rest iterator, combining them into a full iterator again.
Maybe this would be a candidate for an itertools addition?
In addition to the other answers, I want to add that it is useful associated with map for example, to verify that there is only one item that matches a property and to retrieve it.
Suppose that a library returns a whole bunch of items, and only one item has your interest:
let my_item = match get_items().map(|item| item.some_property == reference).single() {
Some(item) => item,
None => return Error,
}
I like the idea of retrieving the original iterator in case of failure, BTW.
it will still consume the first and second items and the original iterator will not have them
@Boiethios was talking about retrieving the iterator, not retrieving elements.
Two consumed elements should be stored in single::Error::MultipleElements(first, second). (Edit: I'm not sure these two elements need to be preserved, but that's not very important).
But then you’ll possibly have to re-assemble the items yourselves in your own error
And retrieving original iterator from single function won't help, because you can't push elements back to the iterator. Returning original iterator from single doesn't solve any problem.
Maybe a generic error type or type parameter that can take what it wants via From<(Item, Item, I)> is the best solution.
From my experience, if something can be done without generic magic, it's better to do it without generics. Otherwise, it leads to code verbosity and compilation errors.
There can be big value in providing customization points via generics. In this case, you can let the library consumer decide how much information they'll want collected.
Result with an error value that provides me with a new iterator
Iterator of a different type than the original iterator.
Looks like overengineering to me.
There can be big value in providing customization points via generics. In this case, you can let the library consumer decide how much information they’ll want collected.
I believe in 99% cases people just want to panic with a meaningful message (empty or more than one). The rest can be done in utility functions in client code.
I assume you don't mean actually panic. But anyway, I don't think I ever wanted a version of this where I didn't customize things depending on context and the other elements.
I can with certainty say that I never wanted to have this functionality panic.
There are no usage statistics for this kind of thing. You can also make an adaptible generic version and have convenient short-paths for the common cases, like with type aliases, helper methods and such.
And if we're talking about the standard libary or a widespread crate, 1% can represent a lot of users.
I can with certainty say that I never wanted to have this functionality panic.
Oh, there's a misunderstanding. single itself should not panic, it should return an error, which can be turned into panic with .unwrap(). Almost exactly the same way implemented by @CAD97.