You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 12:28:13