Rust中如何不使用宏复用get_node与get_node_mut的重复代码?
不用宏消除Rust中可变/不可变函数重复代码的方案
当然可以不用宏,核心思路是通过泛型 trait 抽象可变与不可变引用的访问逻辑,将重复的导航逻辑提取到泛型函数中,让两个公开函数分别调用这个泛型函数即可。
具体实现步骤:
- 定义一个 trait,抽象节点左右子树的获取方式,分别为不可变引用和可变引用实现该 trait:
use std::ops::{Deref, DerefMut}; // 抽象节点子树的访问逻辑 trait NodeAccessor<'a, Key, Item: GetKey<Key>> { type NodeRef; // 获取左子节点 fn left(self) -> Self::NodeRef; // 获取右子节点 fn right(self) -> Self::NodeRef; } // 为不可变引用实现访问逻辑 impl<'a, Key, Item: GetKey<Key>> NodeAccessor<'a, Key, Item> for &'a Node<Key, Item> { type NodeRef = &'a Node<Key, Item>; fn left(self) -> Self::NodeRef { self.left.as_ref().unwrap().deref() } fn right(self) -> Self::NodeRef { self.right.as_ref().unwrap().deref() } } // 为可变引用实现访问逻辑 impl<'a, Key, Item: GetKey<Key>> NodeAccessor<'a, Key, Item> for &'a mut Node<Key, Item> { type NodeRef = &'a mut Node<Key, Item>; fn left(self) -> Self::NodeRef { self.left.as_mut().unwrap().deref_mut() } fn right(self) -> Self::NodeRef { self.right.as_mut().unwrap().deref_mut() } }
- 提取泛型的导航逻辑函数,利用 trait 约束处理两种引用类型:
impl<Key, Item: GetKey<Key>, const K: usize> Bucket<Key, Item, K> { // 通用导航逻辑,接受实现了NodeAccessor的引用类型 fn navigate_node<'a, T>(mut node: T, key: &Key) -> (T, usize) where T: NodeAccessor<'a, Key, Item> + Deref<Target = Node<Key, Item>>, { let mut bit_index = 0; while node.items.is_none() { node = match key.has_bit_at(bit_index) { false => node.left(), true => node.right(), }; bit_index += 1; } (node, bit_index) } // 不可变版本,调用通用函数 pub fn get_node(&self, key: &Key) -> (&Node<Key, Item>, usize) { self.navigate_node(self.root.as_ref(), key) } // 可变版本,调用通用函数 pub fn get_node_mut(&mut self, key: &Key) -> (&mut Node<Key, Item>, usize) { self.navigate_node(self.root.as_mut(), key) } }
方案说明:
- 泛型函数
navigate_node包含了所有重复的导航逻辑,通过trait NodeAccessor的约束,兼容不可变和可变两种引用类型。 - 两个公开函数
get_node和get_node_mut只需要传入对应的初始引用(as_ref/as_mut),调用通用函数即可,完全消除重复代码。 - 这种方式比宏更清晰,类型安全,且易于维护和扩展。
内容的提问来源于stack exchange,提问作者max-lt
相关产品推荐
相关产品推荐

