我有一个能够工作的函数,但它比我想象中更加专业化,并且存在一些低效率的问题,我希望进行改进。
这是一个能够工作但存在缺陷的函数:
fn iter_to_min<T>(i:T) -> i64 where T:Iterator<Item=String>{
i.collect::<Vec<String>>()
.iter()
.flat_map(|s|s.split_whitespace())
.map(str::trim)
.map(str::parse::<i64>)
.map(Result::unwrap)
.min()
.expect("No min found.")
}
我不喜欢这个实现的原因如下:
i64
被硬编码,我希望可以重复使用这个函数并适用于u64
和其他可能的返回类型- 它只是为了立即迭代而收集输入,效率不高(无原因堆分配)
- 传递给
flat_map
的闭包在所有情况下可能都不能被LLVM优化掉
use std::str::FromStr;
fn iter_to_min<T,U>(i:T) -> U where T:Iterator<Item=String>,U: Ord+FromStr{
i.flat_map(str::split_whitespace)
.map(str::trim)
.map(str::parse::<U>)
.map(Result::unwrap)
.min()
.expect("No min found.")
}
我看到的问题如下:
- 传递给
str::split_whitespace
的参数是String
类型,不能强制转换为str
- 传递给
str::split_whitespace
的参数未知是否存在足够长的生命周期 Result::unwrap
报错,因为类型<U as core::str::FromStr>::Err
没有实现特质core::fmt::Debug
我认为,通过巧妙的生命周期标注和特质要求,至少可以解决其中两个问题,也许还有一种方法可以三全其美。
以下是使用一些建议修复的示例代码:
use std::io::BufRead;
use std::str::FromStr;
use std::fmt::Debug;
fn iter_to_min<T,U>(i:T) -> U where T:Iterator<Item=String>,U: Ord+FromStr, U::Err: Debug{
i.collect::<Vec<String>>()
.iter()
.flat_map(|s|s.split_whitespace())
.map(str::trim)
.map(str::parse::<U>)
.map(Result::unwrap)
.min()
.expect("No min found.")
}
fn main() {
let a: Vec<_> = std::env::args().skip(1).collect();
let m:i64 = if a.is_empty() {
let s = std::io::stdin();
let m = iter_to_min(s.lock().lines().map(Result::unwrap));
m
}else{
iter_to_min(a.into_iter())
};
println!("{}", m);
}