假设我们有一个无法进行任何更改的私有库,其中包含一些未在库模块中公开的类型。
// lib.rs
mod inner {
pub struct SecretData {
value: u32,
}
impl SecretData {
fn new(value: u32) -> Self {
SecretData { value }
}
}
pub fn create_secret() -> SecretData {
SecretData::new(42)
}
}
pub use inner::create_secret;
在我们的应用程序中,我们希望使用库提供的函数创建一个秘密,然后打印出该秘密。
// main.rs
use my_crate::create_secret;
fn main() {
let secret = create_secret();
println!("The secret is: {:?}", secret);
}
主函数中的上述代码将导致错误,表明 struct SecretData 尚未实现 Debug 特征。
有什么方法可以打印出
secret
的值吗?
一般情况下不可能。
为了能够从结构中打印有意义的数据,您需要:
std::fmt
的任何显示特征,或者像 Path::display
SecretData
的内存布局,以便您可以自己安全地阅读和打印它。这排除了所有 repr(Rust)
结构。对于您确实知道其内存布局的结构,您可以转换为确实实现显示特征的结构:
mod inner {
#[repr(C)]
pub struct SecretData {
value: u32,
}
impl SecretData {
fn new(value: u32) -> Self {
SecretData { value }
}
}
pub fn create_secret() -> SecretData {
SecretData::new(42)
}
}
use inner::create_secret;
#[repr(C)]
#[derive(Debug)]
struct NotSoSecret {
v: u32,
}
fn main() {
let secret = create_secret();
// # Safety:
// Both `SecretData` and `NotSoSecret` are `#[repr(C)]` strutcs with a single `u32` field so they both have the same memory layout.
println!("The secret is: {:?}", unsafe {
std::mem::transmute::<_, NotSoSecret>(secret)
});
}
注意:两者
#[repr(C)]
都是必需的,否则内存布局未指定。
因为您知道
SecretData
的结构,所以可以创建您自己的相同形状的结构和 transmute
您可访问的秘密结构 SpyData
:
pub struct SpyData {
value: u32,
}
let secret = create_secret();
let spied: SpyData = unsafe { std::mem::transmute(secret) };
println!("The secret is: {}", spied.value); // 42