如何在Rust中声明映射字符串切片到近似签名函数的静态phf::Map?
如何用静态phf::Map映射返回不同错误类型的相似签名函数?
我需要声明一个静态phf::Map变量,用于将特定字符串切片映射到若干签名近乎一致的函数,但实现难度超出预期。
经过一番尝试后,我得到了简化版代码(如下所示),其中已消除phf::Map第一个条目的警告,但目前因第二个函数返回serde_yaml::Error而陷入困境。
我曾考虑用泛型替代函数指针中的serde_json::Error,但这不可行:
phf::Map<&str, fn<E: std::error::Error>(File) -> Result<Config, E>>
编译器提示:function pointer types may not have generic。
目前我能想到的唯一解决方案是用签名完全一致的函数包装每个serde函数,这需要创建通用错误类型或枚举并编写额外函数,但我希望避免这种做法。鉴于我的Rust经验有限,我认为可能存在自己尚未知晓的巧妙技巧。
注意:我不寻求模式匹配、延迟求值等替代方案,且只关注上述描述的问题。
尝试的代码片段
use phf::phf_map; use std::fs::File; use std::path::Path; type Config = Vec<String>; static loaders: phf::Map<&str, fn(File) -> Result<Config, serde_json::Error>> = phf_map! { "json" => serde_json::from_reader, "yaml" => serde_yaml::from_reader, }; fn load<P: AsRef<Path>, E: std::error::Error>(filepath: P) -> Result<Config, E>{ let extension = filepath.as_ref().extension().unwrap().to_str().unwrap(); match loaders.get(extension) { Some(loader) => { let reader = File::open(filepath).unwrap(); loader(reader) }, None => panic!("Invalide extension"), } } fn main() { let filepath = Path::new("conf.json"); let conf = load(filepath); println!("{:?}", conf) }
编译错误信息
error[E0308]: mismatched types --> src/main.rs:113:15 | 113 | "yaml" => serde_yaml::from_reader, | ^^^^^^^^^^^^^^^^^^^^^^^ expected fn pointer, found fn item | = note: expected fn pointer `fn(File) -> Result<Vec<std::string::String>, serde_json::Error>` found fn item `fn(_) -> Result<_, serde_yaml::Error> {serde_yaml::from_reader::<_, _>}` = note: when the arguments and return types match, functions can be coerced to function pointers error[E0308]: mismatched types --> src/main.rs:126:13 | 117 | fn load<P: AsRef<Path>, E: std::error::Error>(filepath: P) -> Result<Config, E>{ | - this type parameter ----------------- expected `Result<Vec<std::string::String>, E>` because of return type ... 126 | loader(reader) | ^^^^^^^^^^^^^^ expected `Result<Vec<String>, E>`, found `Result<Vec<String>, Error>` | = note: expected enum `Result<_, E>` found enum `Result<_, serde_json::Error>` error[E0282]: type annotations needed --> src/main.rs:140:16 | 140 | let conf = load(filepath); | ^^^^ cannot infer type of the type parameter `E` declared on the function `load` | help: consider specifying the generic arguments | 140 | let conf = load::<&Path, E>(filepath); | ++++++++++++
内容的提问来源于stack exchange,提问作者c0deca1ne
相关产品推荐
相关产品推荐

