如何修改Rust代码使Block 2生效并适配不同类型?
问题描述
当前Block 1代码可正常运行,输出:"abc" 和 49。如何修改代码让Block 2替代Block 1生效?要求不能将trait Trt中的f01方法改为带返回值的形式(即不能写成fn f01(&self) -> ...;)。
原代码如下:
struct Dom {a: String,} struct Num {a: u8,} trait Trt { fn f01(&self); } impl Trt for Dom { fn f01(&self) { println!("{:?}", &self.a); } } impl Trt for Num { fn f01(&self) { println!("{:?}", &self.a * &self.a); } }
fn main() { let dom = Dom {a: "abc".to_string()}; let num = Num {a: 7}; // Block 1: Trt::f01(&dom); // "abc" Trt::f01(&num); // 49 // Block 2: // Trt::f01(&dom); // "abc" // let b: u8 = Trt::f01(&num) + 1; // println!("{:?}", b); // 50 }
解决方案
由于不能修改Trt中f01的无返回值签名,我们可以扩展trait新增一个计算方法,让f01内部调用该方法完成打印,同时允许外部直接调用计算方法获取值进行后续操作,既保留原有功能,又满足Block 2的需求。
推荐方案(扩展Trait)
修改后的完整代码:
struct Dom { a: String } struct Num { a: u8 } trait Trt { fn f01(&self); // 新增关联类型定义计算结果类型 type Output; fn compute(&self) -> Self::Output; } impl Trt for Dom { type Output = &str; // 实现Dom的计算逻辑 fn compute(&self) -> &str { &self.a } // f01复用compute的结果完成打印 fn f01(&self) { println!("{:?}", self.compute()); } } impl Trt for Num { type Output = u8; // 实现Num的计算逻辑 fn compute(&self) -> u8 { self.a * self.a } // f01复用compute的结果完成打印 fn f01(&self) { println!("{:?}", self.compute()); } } fn main() { let dom = Dom { a: "abc".to_string() }; let num = Num { a: 7 }; // Block 2 生效代码 Trt::f01(&dom); // 输出 "abc" let b: u8 = num.compute() + 1; // 49 + 1 = 50 println!("{:?}", b); // 输出 50 }
可选方案(内部可变性,不推荐)
如果严格不想修改trait定义,可以用RefCell在Num的f01中存储计算结果,但会引入内部可变性,代码可读性和安全性较差:
use std::cell::RefCell; struct Dom { a: String } struct Num { a: u8, result: RefCell<Option<u8>>, } trait Trt { fn f01(&self); } impl Trt for Dom { fn f01(&self) { println!("{:?}", &self.a); } } impl Trt for Num { fn f01(&self) { let res = self.a * self.a; *self.result.borrow_mut() = Some(res); println!("{:?}", res); } } fn main() { let dom = Dom { a: "abc".to_string() }; let num = Num { a: 7, result: RefCell::new(None) }; Trt::f01(&dom); // 输出 "abc" Trt::f01(&num); // 输出 49 let b: u8 = num.result.borrow().unwrap() + 1; println!("{:?}", b); // 输出 50 }
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

