所以我知道将不可变引用转换为可变引用是UB。然而,如果不可变引用是从可变引用派生的,那么它是否仍然被认为是 UB,因为从技术上讲,内存应该已经被视为可变的?或者这仍然是 UB,因为事实上不可变引用曾经是可变的,完全不相关,并且考虑到从可变 -> 不可变的转换会消耗原始可变引用,它仍然会将引用视为不可变?
更具体地说,假设我有一个像这样的树结构:
pub struct Schema {
pub name: String,
pub fields: Vec<SchemaNode>,
pub types: BTreeMap<String, ComplexType>,
}
pub struct SchemaNode {
pub name: String,
pub dtype: DType,
}
pub enum DType {
Base(),
Complex {
name: String,
},
}
pub struct ComplexType {
pub children: Vec<SchemaNode>,
}
impl Schema {
pub fn query(&self, query: &str) -> Option<&SchemaNode> {
let mut fragments = query.split(".");
let name = fragments.next()?;
let mut node = self.fields.iter().filter(|n| n.name == name).next()?;
// continue down if required
for name in fragments {
match &node.dtype {
DType::Base => return None,
DType::Complex { name: type_name } => {
node = self
.types
.get(type_name)?
.children
.iter()
.filter(|c| c.name == name)
.next()?;
}
};
}
Some(node)
}
}
如果我想添加一个query_mut方法,这样做可以吗:
impl Schema {
pub fn query_mut<'a>(&'a mut self, query: &str) -> Option<&'a mut SchemaNode> {
let node = self.query(query)?;
unsafe {
let const_ptr = node as *const SchemaNode;
let mut_ptr = const_ptr as *mut SchemaNode;
mut_ptr.as_mut()
}
}
}
在这种情况下,我知道可以编写 query_mut,然后从 query_mut 派生查询,但由于它当前的结构,您会遇到可变性问题,因为 Schema.types 会在循环内多次借用。
是的,这是无效的。
引用经济学:
- 将
转换为&
是未定义的行为。虽然某些用法可能 出现安全,请注意,Rust 优化器可以自由地假设共享 引用在其生命周期内不会改变,因此这种转变将 与这些假设相冲突。所以:&mut
- 将
转换为&
是始终 未定义的行为。&mut
- 不,你做不到。
- 不,你并不特别。
单独写一个
query_mut()
是 正确的方法。