Rust trait实现中避免重复代码的惯用方法(rustlings TryFrom案例)
几种常用的避免重复代码的写法,都是Rust社区的惯用方案:
1. 优先用闭包替代内部函数
闭包可以直接继承外层作用域的类型、变量,不需要显式声明泛型或者关联类型,完美适配你这个场景:
fn try_from(tuple: (i16, i16, i16)) -> Result<Self, Self::Error> { #[inline] let convert = |val| u8::try_from(val).map_err(|_| IntoColorError::IntConversion); Ok(Self { red: convert(tuple.0)?, green: convert(tuple.1)?, blue: convert(tuple.2)?, }) }
不需要额外定义独立函数,逻辑内聚,也没有任何性能损耗。
2. 元组转数组没有额外性能开销,完全可以放心用
固定长度同类型元组转数组的操作是纯编译期转换,运行时零成本,你完全可以直接把元组转为数组后复用数组版本的逻辑,不需要重复写代码:
fn try_from(tuple: (i16, i16, i16)) -> Result<Self, Self::Error> { [tuple.0, tuple.1, tuple.2].try_into() }
这种写法最简洁,编译器会自动调用你已经实现好的数组版本的TryFrom,完全没有冗余。
3. 跨impl复用逻辑可以直接定义模块级私有函数
你这个场景下TryFrom的关联错误类型IntoColorError是固定的,不需要依赖Self::Error,直接在当前模块下定义私有辅助函数即可,所有同模块的impl块都可以调用:
// 模块内私有,只有当前模块能访问 #[inline] fn i16_to_color_channel(val: i16) -> Result<u8, IntoColorError> { u8::try_from(val).map_err(|_| IntoColorError::IntConversion) } // 之后所有impl块里都可以直接调用这个函数 impl TryFrom<(i16, i16, i16)> for Color { type Error = IntoColorError; fn try_from(tuple: (i16, i16, i16)) -> Result<Self, Self::Error> { Ok(Self { red: i16_to_color_channel(tuple.0)?, green: i16_to_color_channel(tuple.1)?, blue: i16_to_color_channel(tuple.2)?, }) } }
顺便优化下你原来的数组版本实现
你原来的写法用到了collect到Vec,会产生不必要的堆分配,其实可以用数组原生的map方法直接在栈上处理,性能更好也更符合惯用写法:
impl TryFrom<[i16; 3]> for Color { type Error = IntoColorError; fn try_from(arr: [i16; 3]) -> Result<Self, Self::Error> { let [r, g, b] = arr.map(i16_to_color_channel); Ok(Self { red: r?, green: g?, blue: b?, }) } }
内容的提问来源于stack exchange,提问作者thisisrandy
相关产品推荐
相关产品推荐

