环境变量的读取看似一行代码,却牵出编码、可变性、进程边界与编译期差异。这篇逐条验证 env::var 的各种结果、set_var 为什么变成 unsafe、子进程的修改是否可见,以及 env! 与 env::var 的区别。
U147_SET var = Ok("hello") var_os = Some("hello")
U147_MISSING var = Err("environment variable not found") var_os = None
U147_BAD var = Err("environment variable was not valid unicode: \"bad\\xFF\\xFE\"") var_os = Some("bad\xFF\xFE")
U147_EMPTY var = Ok("") var_os = Some("")
U147_EMPTY 是空字符串不是不存在:Ok(true)
var_os 比 var 能装下非 UTF-8 的值:Some([98, 97, 100, 255, 254])子进程如何继承与修改环境见子进程与 Command。
源码:
1 | use std::{env, process::Command};
2 | fn main() {
3 | unsafe { env::set_var("U147_X", "from-rust"); }
4 | let o = Command::new("sh").arg("-c").arg("echo child sees U147_X=$U147_X").output().unwrap(); println!("set_var 之后子进程看到:{}", String::from_utf8_lossy(&o.stdout).trim());
5 | unsafe { env::remove_var("U147_X"); }
6 | let o = Command::new("sh").arg("-c").arg("echo child sees U147_X=[$U147_X]").output().unwrap(); println!("remove_var 之后子进程看到:{}", String::from_utf8_lossy(&o.stdout).trim());
7 | }
编译:成功
运行(退出码 0):
set_var 之后子进程看到:child sees U147_X=from-rust
remove_var 之后子进程看到:child sees U147_X=[]
源码:
1 | fn main() { std::env::set_var("A", "1"); }
编译:失败
error[E0133]: call to unsafe function `set_var` is unsafe and requires unsafe block
--> <实验目录>/src/u147c.rs:1:13
|
1 | fn main() { std::env::set_var("A", "1"); }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
|
= note: consult the function's documentation for information on how to avoid undefined behavior
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0133`.unsafe 的含义见unsafe 的安全边界。
编译:成功
运行(退出码 0):
child: child
子进程改完之后,父进程仍然是 Ok("parent")环境里放一个非 UTF-8 的变量:vars → 退出码 101,stdout '',stderr ["thread 'main' (7496955) panicked at /rustc/48a229ceaefd4985c50990b14116b6d856af0985/library/std/src/env.rs:168:83:", 'called `Result::unwrap()` on an `Err` value: "bad\\xFF\\xFE"'] 环境里放一个非 UTF-8 的变量:vars_os → 退出码 0,stdout 'vars_os() 共 58 个',stderr []
编译时设置 A,运行时设置 B:编译期 option_env! = Some("A-at-compile");运行期 env::var = Some("B-at-run")
编译时没设置,运行时设置 B:编译期 option_env! = None;运行期 env::var = Some("B-at-run")
env!("U147_REQUIRED") 编译期缺失:['error: environment variable `U147_REQUIRED` not defined at compile time']build.rs 里的 cargo:rustc-env 见Build Script build.rs。