functional-programming - 使用迭代器时的类型感知映射
问题描述
我有以下代码:
fn main() {
let xs = vec!["1i32".to_string(), "2".to_string(), "3".to_string()];
let ys = do_some(xs);
println!("{:?}", ys);
}
fn do_some(tokens: Vec<String>) -> Result<Vec<String>, bool> {
tokens
.into_iter()
.map(|token: String| Ok(token))
.map(|token: Result<String, bool>| token.map(|s| s + "a"))
.fold(Ok(Vec::new()), |acc, s| acc.push(s))
}
在 line 之后.map(|token| Ok(token))
,我希望调用map
会起作用Result
而不是起作用Iterator
,因此能够解开Result
,但我得到Result<String, bool>
的输出数据是:
error[E0599]: no method named `push` found for type `std::result::Result<std::vec::Vec<std::string::String>, bool>` in the current scope
--> src/main.rs:12:44
|
12 | .fold(Ok(Vec::new()), |acc, s| acc.push(s))
| ^^^^
在 Rust 中编写函数式代码的最佳方法是什么?
我知道,and_then
但似乎无法在此链中使用。
解决方案
我不能真正告诉你究竟在追求什么,但是 - 从签名来看do_some
- 我想你有一个Vec<String>
, 一个函数正在运行String
,返回一个Result<String, bool>
,并且你想将此函数应用于 中的每个元素Vec
,并获取它们变成一个Vec
如果一切都是Ok
。如果你遇到一个Err
,你想返回一个Err
。这可以通过以下方式实现:
fn do_some(tokens: Vec<String>) -> Result<Vec<String>, bool> {
tokens
.into_iter()
.map(|token: String| Ok(token)) // or any other Fn(String)->Result<String, bool>
.map(|token: Result<String, bool>| token.map(|s| s + "a"))
.collect()
}
这使用collect
,依赖FromIter
,您可以将s上的迭代器转换Result
Result
为。
请注意,您可以使所有这些更通用:
- 输入不需要是 a
Vec
,它可以是一个Iterator
overString
s。 String
我们可以通过将 single 转换为a的转换函数对其进行参数化Result<String, bool>
,或者 - 更通用地 - 转换为 aResult<String, ErrorType>
for someErrorType
。- 您不一定需要 a
Vec
作为成功的返回类型,而是需要任何实现FromIter
(通常是容器类型)。
执行此操作的第一步可能如下所示:
fn do_some<
ErrorType,
Tokens: std::iter::IntoIterator<Item=String>, // an iterable yielding String
StringToResult: Fn(String) -> Result<String, ErrorType>,
>(
tokens: Tokens,
string_to_result: StringToResult,
) -> Result<Vec<String>, ErrorType> {
tokens
.into_iter()
.map(|s| string_to_result(s).map(|s| s + "a"))
.collect()
}
可以按如下方式使用:
fn main() {
println!("{:?}",
do_some(vec!["i1".to_string(), "i2".to_string(), "i3".to_string()], |s| {
if s.starts_with("i") {
Ok(s)
} else {
Err(s + " i does not start with i")
}
})
);
println!("{:?}",
do_some(vec!["i1".to_string(), "i2".to_string(), "A3".to_string()], |s| {
if s.starts_with("i") {
Ok(s)
} else {
Err(s + " i does not start with i")
}
})
);
}
推荐阅读
- java - 应用程序服务未在启动时启动
- scala - Akka:将 PoisonPill 发送到 Master 与终止系统上下文
- html - 如何在 IE11 中禁用锚元素中的换行符
- mongodb - 如何在嵌入式文档上查询 $regex 以计算不同的值
- javascript - jQuery滚动到可滚动div卡住循环中的元素顶部
- java - 多捕获异常处理和多态性
- php - codeigniter 显示 stream_socket_client(): Failed to enable crypto 这个错误在 sendmail 上?
- docker - KVM 模块未加载到容器中
- java - 在带有 Itextpdf 的 Times-New-Roman 字体中使用度数符号
- xml - 从变量加载 XML 和 XSL 并在浏览器中转换