我在读的一条Rust语句让我很难理解。你能解释一下吗?
我在努力理解为什么一个OpenAPI生成器会产出错误的Rust源代码。为此,我首先要理解我正在看的这段表达式(因为它位于一个无法编译的代码块中,我无法测试它)。
当一个 param_filter 先前已被 let param_filter =... 赋值,语句是:
let param_filter =
<std::collections::HashMap<String, String> as std::str::FromStr>::from_str(¶m_filter);
这条语句到底会做什么?
分解成几个小问题:
- 一个
<std::collections::HashMap<String, String> as std::str::FromStr>表示什么? - 而且它上面的
::from_str(¶m_filter)又意味着什么? - 它会尝试把什么赋给
param_filter变量?
这条语句位于以下代码块中:
// Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response)
let query_params = form_urlencoded::parse(uri.query().unwrap_or_default().as_bytes()).collect::<Vec<_>>();
let param_filter = query_params.iter().filter(|e| e.0 == "filter").map(|e| e.1.clone())
.next();
let param_filter = match param_filter {
Some(param_filter) => {
let param_filter =
<std::collections::HashMap<String, String> as std::str::FromStr>::from_str
(¶m_filter);
match param_filter {
Ok(param_filter) => Some(param_filter),
Err(e) => return Ok(Response::builder()
.status(StatusCode::BAD_REQUEST)
.body(body_from_string(format!("Couldn't parse query parameter filter - doesn't match schema: {e}")))
.expect("Unable to create Bad Request response for invalid query parameter filter")),
}
},
None => None,
};
在编译阶段引发了如下问题:
<std::collections::HashMap<String, String> as std::str::FromStr>::from_str
^^^^ the trait `FromStr` is not implemented for `HashMap<std::string::String, std::string::String>`
= help: the following other types implement trait `FromStr`:
AnyOf10<A, B, C, D, E, F, G, H, I, J>
AnyOf11<A, B, C, D, E, F, G, H, I, J, K>
AnyOf12<A, B, C, D, E, F, G, H, I, J, K, L>
AnyOf13<A, B, C, D, E, F, G, H, I, J, K, L, M>
AnyOf14<A, B, C, D, E, F, G, H, I, J, K, L, M, N>
AnyOf15<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O>
AnyOf16<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P>
AnyOf1<A>
and 145 others
我并不是要你解决这个问题。
我只是想了解OpenAPI生成器在我向你展示的这条唯一语句中,使用 rust-axum 生成器写了些什么。
背景信息:
我需要找到能够处理大型REST YAML规范的开发语言,例如TM Forum的规范,这是一个面向企业或专业人士的开源标准。
我已经用以下语言对它们进行了测试:rust-server, rust-axum, spring, python-flask, python-fastapi, typescript-nestjs-server, nodejs-express-server, go-server, go-gin-server, cpp-oatpp-server, cpp-pistache-server。
目前,只有 spring(Java)、python-fastapi 和 nodejs-express-server 能从我拥有的TM Forum规范集合中生成可编译的源码。其他都失败。
不过 rust-axum 也不远了。
解决方案
在理解代码时,我建议采取自上而下的方式。
对于以下代码:
<std::collections::HashMap<String, String> as std::str::FromStr>::from_str(¶m_filter)
这意味着要认识到顶层表达式是形式为 <type>::<function>(<arguments...>) 的限定函数调用。
这种形式的一个更简单的例子是 u64::count_ones(i),一个更接近的例子是 FromStr::from_str(¶m_filter)。
这一部分的类型有点怪,因为 from_str 是来自 FromStr 这一trait的一个函数。由于一个trait可以被多种类型实现,且类型推断可能无法推断出该类型,因此这里有一个完全显式的写法可用,在此使用:<Type as Trait>::function,它表示 function 是 Trait 的成员,我们正在专门寻求对 Type 使用 Trait 的实现。
因此,我们已经把所有部分拼凑在一起:
- 这是对
std::str::FromStr::from_str的调用,它把&str作为参数并返回Result<Self, Self::Err>。 - 专门针对
std::collections::HashMap<String, String>类型。
FromStr trait用于实现解析(parsing),通常与用于实现格式化的 Display trait相辅相成——也就是说,如果两者都实现,它们应该能够实现来回转换。
然而,错误信息指出,FromStr 未在 HashMap 上实现,事实上,它甚至没有在标准库的任何集合类型上实现过(甚至连 Option 也没有)。
这段代码必须被一个专门的函数调用所替代(该函数可能已经存在,也可能还不存在),用于将字符串解析成 HashMap<String, String>,或者在解析失败时返回错误。