什么是条件求值的替代方法,如Rust const函数中的if或match?

什么是条件求值的替代方法,如Rust const函数中的if或match?,rust,constants,Rust,Constants,我有一段代码,它根据环境名称读取config.toml文件,并为整个项目提供所有配置设置 const fn get_conf() -> toml::Value { let file_name = match env::var("ENVIRONMENT") { Ok(val) => val.to_lowercase(), Err(_e) => "development".to_lowercase(),

我有一段代码,它根据环境名称读取config.toml文件,并为整个项目提供所有配置设置

const fn get_conf() -> toml::Value {
    let file_name = match env::var("ENVIRONMENT") {
        Ok(val) => val.to_lowercase(),
        Err(_e) => "development".to_lowercase(),
    };

    let content = fs::read_to_string(format!("conf/{}.toml", file_name)).unwrap();
    let conf: Value = toml::from_str(content.as_str()).unwrap();

    conf
}

static mut CONFIG: toml::Value = get_conf();
我得到一个错误:

错误[E0658]:`match`在`const fn中不允许出现`
-->src/lib.rs:2:21
|
2 |让文件名=匹配环境::变量(“环境”){
|  _____________________^
3 | | Ok(val)=>val.to_小写(),
4 | | Err(_e)=>“development”,
5 | |     };
| |_____^
|
=注:有关更多信息,请参阅第49146期

这在Rust nightly中得到了解决,但我不想在生产中使用nightly构建。在常量函数中使用匹配或if条件是否有任何解决方法?

不可能使用带有稳定分支的
常量fn
。此外,您使用的不是常量fn,因此不能用于其他常量fn。我相信您的意思是,它在编译时而不是执行时检索环境变量

Fow现在一个可能的“解决方法”是,它有点笨拙但功能强大。采用该方法时,流程如下所示:

//build.rs
使用std::path::path;
使用std::env;
使用std::fs::File;
fn main(){
让path=path::new(env::var(“OUT_DIR”).unwrap().as_str()).join(“gen.rs”);
文件::创建(路径)
.expect(“gen.rs创建失败”)
.全部写(“”)
.expect(“gen文件写入失败”)
}
然后,您可以将生成的文件与直接文件一起使用,包括:

//main.rs或任何其他文件
包括!(concat!(env!(“OUT_DIR”),“/gen.rs”);

常量表达式中条件的主要替代方法是将布尔值转换为
usize
s,并将其用作结果值数组的索引:

const fn demo(is_enabled: bool) -> i32 {
    let choices = [
        0,  // false
        42, // true
    ];
    
    choices[is_enabled as usize]
}
这可以(痛苦地)扩展到越来越多的情况:

const fn sign(count: i32) -> i32 {
    let is_pos = count > 0;
    let is_zero = count == 0;
    
    [[-1, 0], [1, 0]][is_pos as usize][is_zero as usize]    
}

fn main() {
    dbg!(sign(-2));
    dbg!(sign(-0));
    dbg!(sign(2));
}
另见:


对于您的实际用例,您应该只使用一个惰性全局值:

use once_cell::sync::Lazy; // 1.4.0
use std::{env, fs};

static mut CONFIG: Lazy<toml::Value> = Lazy::new(|| {
    let file_name = match env::var("ENVIRONMENT") {
        Ok(val) => val.to_lowercase(),
        Err(_e) => "development".to_lowercase(),
    };

    let content = fs::read_to_string(format!("conf/{}.toml", file_name)).unwrap();
    toml::from_str(content.as_str()).unwrap()
});
use once_cell::sync::Lazy;//1.4.0
使用std::{env,fs};
静态mut配置:Lazy=Lazy::new(| |){
让file_name=match env::var(“环境”){
Ok(val)=>val.to_小写(),
Err(_e)=>“development”。to_小写(),
};
让content=fs::read_to_string(format!(“conf/{}.toml”,文件名)).unwrap();
toml::from_str(content.as_str()).unwrap()
});
另见:

一些核心语言功能现在允许在
const fn
中使用

常数fn改进

您现在可以在const中使用几个核心语言特性 fn:


你好我也不能让它每晚运行:。此外,我怀疑是否可以分别读取
常量fn
中的环境变量。提供有意义的结果。您确定想要一个
常量fn
,还是只想找一些东西来初始化
配置
?如果是这样,
lazy\u static
可能会对您有所帮助。Const函数在编译时执行,因此如果它起作用,将完全冻结您的配置,就像编译软件时一样,这看起来不像配置文件的正常使用。正如@phimuemue所说,您确定它不是您想要的
lazy\u static
,这样在初始化软件时配置文件只读取一次吗?lazy\u static似乎是一个很好的解决方案,但当我运行lazy\u static时!{pub static CONFIG:Value=get_conf();},它会给我错误“宏调用中不需要此令牌的任何规则”和“
match
const fn
中是不允许的”
env将无法编译,因此要么没有要处理的故障模式,要么需要使用
选项\u env(但同样的问题是const fns当前无法执行条件)。代码编译良好,但在调试CLion获取配置值时“-var create:无法创建变量对象”。
if, if let, and match
while, while let, and loop
the && and || operators