Unfortunately, you cannot do what you want, keeping both the general and the lack of distribution. The reason is because you need someone who owns your string data, but if flat_map(str::split_whitespace) is executed on the iterator of its lines, then there is no one to save these owned lines more, because str::split_whitespace only takes the line on which it is called, However, if you βpressβ the ownership of the call chain, you cannot be completely generic and accept the lines belonging to them by value.
Therefore, there are two solutions: either cast the entire iterator to Vec<String> (or convert the elements provided by split_whitespace() to their own lines and put them together again in Vec ) or accept the link iterator.
Here is the most general version that I could find in the first solution:
use std::str::FromStr; use std::fmt::Debug; fn iter_to_min<S, T, U>(i: T) -> U where S: Into<String>, T: IntoIterator<Item=S>, U: Ord + FromStr, U::Err: Debug { i.into_iter() .map(Into::into) .collect::<Vec<_>>() .iter() .flat_map(|s| s.split_whitespace()) .map(str::parse::<U>) .map(Result::unwrap) .min() .expect("No min found") }
(try here )
This is basically the same as your first, but more general. Also note that you do not need to trim parts of the line after split_whitespace() - the latter will make sure that the parts of the line do not have spaces on the sides. Into<String> allows you to skip the iterators &str and String , and in the latter case, additional copies will not be executed.
Alternatively, you can split each line into its own lines separately:
fn iter_to_min<S, T, U>(i: T) -> U where S: AsRef<str>, T: IntoIterator<Item=S>, U: Ord + FromStr, U::Err: Debug { i.into_iter() .flat_map(|s| s.as_ref().split_whitespace().map(String::from).collect::<Vec<_>>()) .map(|s| s.parse::<U>()) .map(Result::unwrap) .min() .expect("No min found") }
Here we need to get only &str from the elements of the iterator, not String s, so I used AsRef<str> . However, each string must not only be converted to a sequence of String s; this sequence must be assembled into a vector for the same reason that was mentioned above - otherwise there would be no one to save the initial values ββof type S from destruction.
But you can avoid .map(String::from).collect::<Vec<_>>() if you want to lose some pedigree. This is the second solution that I mentioned above. We can take an iterator for links:
fn iter_to_min<'a, S: ?Sized, T, U>(i: T) -> U where S: AsRef<str> + 'a, T: IntoIterator<Item=&'a S>, U: Ord + FromStr, U::Err: Debug { i.into_iter() .map(AsRef::as_ref) .flat_map(str::split_whitespace) .map(|s| s.parse::<U>()) .map(Result::unwrap) .min() .expect("No min found") }
(try here )
Roughly speaking, now the values ββof S belong to someone else, and their lifetime is longer than the scope of iter_to_min() , so you do not need to convert each part to String , or collect the entire result of splitting a Vec<String> . However, you cannot pass Vec<String> this function; you can pass vec.iter() , however:
let v: Vec<String> = vec!["0".into(), "1".into()]; iter_to_min(v.iter())
In all of these examples, I changed Iterator to IntoIterator - this is almost always what you want to use, not just Iterator . It allows, for example, to pass collections to such functions directly. Secondly, I added the U::Err: Debug condition, which is necessary for Result::unwrap to work. And finally, to fix the problem with "A string that does not force & str", you can always use explicit closures and the syntax of a method that would do this enforcement for you.