有没有办法使不可变引用可变?
Is there a way to make an immutable reference mutable?
我想用 Rust 解决一个 leetcode 问题 (Remove Nth Node From End of List)。我的解决方案使用两个指针来找到要删除的 Node
:
#[derive(PartialEq, Eq, Debug)]
pub struct ListNode {
pub val: i32,
pub next: Option<Box<ListNode>>,
}
impl ListNode {
#[inline]
fn new(val: i32) -> Self {
ListNode { next: None, val }
}
}
// two-pointer sliding window
impl Solution {
pub fn remove_nth_from_end(head: Option<Box<ListNode>>, n: i32) -> Option<Box<ListNode>> {
let mut dummy_head = Some(Box::new(ListNode { val: 0, next: head }));
let mut start = dummy_head.as_ref();
let mut end = dummy_head.as_ref();
for _ in 0..n {
end = end.unwrap().next.as_ref();
}
while end.as_ref().unwrap().next.is_some() {
end = end.unwrap().next.as_ref();
start = start.unwrap().next.as_ref();
}
// TODO: fix the borrow problem
// ERROR!
// start.unwrap().next = start.unwrap().next.unwrap().next.take();
dummy_head.unwrap().next
}
}
我借用了链表的两个不可变引用。找到要删除的目标节点后,我想删除一个并使另一个可变。以下每个代码示例都会导致编译器错误:
// ERROR
drop(end);
let next = start.as_mut().unwrap.next.take();
// ERROR
let mut node = *start.unwrap()
我不知道这个解决方案是否可以用 Rust 编写。如果我可以使不可变引用可变,我该怎么做?如果没有,是否有实现相同逻辑的同时让借用检查器开心的方法?
Is there a way to make an immutable reference mutable?
没有
您可以编写不安全的 Rust 代码来强制类型对齐,但代码实际上是不安全的并会导致 未定义的行为。你不想要这个。
对于您的具体问题,请参阅:
正确答案是您不应该这样做。这是未定义的行为,并且打破了编译器在编译程序时所做的许多假设。
但是,可以这样做。其他人也提到了为什么这不是一个好主意,但他们实际上并没有显示执行此类操作的代码是什么样的。尽管你不应该这样做,但它看起来应该是这样的:
unsafe fn very_bad_function<T>(reference: &T) -> &mut T {
let const_ptr = reference as *const T;
let mut_ptr = const_ptr as *mut T;
&mut *mut_ptr
}
本质上,您将常量指针转换为可变指针,然后将可变指针变为引用。
这是一个非常不安全和不可预测的例子:
fn main() {
static THIS_IS_IMMUTABLE: i32 = 0;
unsafe {
let mut bad_reference = very_bad_function(&THIS_IS_IMMUTABLE);
*bad_reference = 5;
}
}
如果你 运行 这个...你会遇到段错误。发生了什么?本质上,您通过尝试写入已标记为不可变的内存区域来使内存规则无效。从本质上讲,当您使用这样的函数时,您破坏了编译器对您的信任,不会弄乱常量内存。
这就是为什么你永远不应该使用它,尤其是在 public API 中,因为如果有人将无辜的不可变引用传递给你的函数,并且您的函数对其进行了修改,并且引用指向了一个不应该写入的内存区域,您将得到一个段错误。
简而言之:不要试图欺骗借阅检查员。这是有原因的。
编辑:除了我刚才提到的为什么这是未定义行为的原因外,另一个原因是违反了引用别名规则。也就是说,由于您可以同时拥有对变量的可变引用和不可变引用,因此当您将它们分别传递给同一函数时会导致大量问题,该函数假定不可变引用和可变引用是唯一的。阅读 Rust 文档中的 this page 了解更多相关信息。
我想用 Rust 解决一个 leetcode 问题 (Remove Nth Node From End of List)。我的解决方案使用两个指针来找到要删除的 Node
:
#[derive(PartialEq, Eq, Debug)]
pub struct ListNode {
pub val: i32,
pub next: Option<Box<ListNode>>,
}
impl ListNode {
#[inline]
fn new(val: i32) -> Self {
ListNode { next: None, val }
}
}
// two-pointer sliding window
impl Solution {
pub fn remove_nth_from_end(head: Option<Box<ListNode>>, n: i32) -> Option<Box<ListNode>> {
let mut dummy_head = Some(Box::new(ListNode { val: 0, next: head }));
let mut start = dummy_head.as_ref();
let mut end = dummy_head.as_ref();
for _ in 0..n {
end = end.unwrap().next.as_ref();
}
while end.as_ref().unwrap().next.is_some() {
end = end.unwrap().next.as_ref();
start = start.unwrap().next.as_ref();
}
// TODO: fix the borrow problem
// ERROR!
// start.unwrap().next = start.unwrap().next.unwrap().next.take();
dummy_head.unwrap().next
}
}
我借用了链表的两个不可变引用。找到要删除的目标节点后,我想删除一个并使另一个可变。以下每个代码示例都会导致编译器错误:
// ERROR
drop(end);
let next = start.as_mut().unwrap.next.take();
// ERROR
let mut node = *start.unwrap()
我不知道这个解决方案是否可以用 Rust 编写。如果我可以使不可变引用可变,我该怎么做?如果没有,是否有实现相同逻辑的同时让借用检查器开心的方法?
Is there a way to make an immutable reference mutable?
没有
您可以编写不安全的 Rust 代码来强制类型对齐,但代码实际上是不安全的并会导致 未定义的行为。你不想要这个。
对于您的具体问题,请参阅:
正确答案是您不应该这样做。这是未定义的行为,并且打破了编译器在编译程序时所做的许多假设。
但是,可以这样做。其他人也提到了为什么这不是一个好主意,但他们实际上并没有显示执行此类操作的代码是什么样的。尽管你不应该这样做,但它看起来应该是这样的:
unsafe fn very_bad_function<T>(reference: &T) -> &mut T {
let const_ptr = reference as *const T;
let mut_ptr = const_ptr as *mut T;
&mut *mut_ptr
}
本质上,您将常量指针转换为可变指针,然后将可变指针变为引用。
这是一个非常不安全和不可预测的例子:
fn main() {
static THIS_IS_IMMUTABLE: i32 = 0;
unsafe {
let mut bad_reference = very_bad_function(&THIS_IS_IMMUTABLE);
*bad_reference = 5;
}
}
如果你 运行 这个...你会遇到段错误。发生了什么?本质上,您通过尝试写入已标记为不可变的内存区域来使内存规则无效。从本质上讲,当您使用这样的函数时,您破坏了编译器对您的信任,不会弄乱常量内存。
这就是为什么你永远不应该使用它,尤其是在 public API 中,因为如果有人将无辜的不可变引用传递给你的函数,并且您的函数对其进行了修改,并且引用指向了一个不应该写入的内存区域,您将得到一个段错误。
简而言之:不要试图欺骗借阅检查员。这是有原因的。
编辑:除了我刚才提到的为什么这是未定义行为的原因外,另一个原因是违反了引用别名规则。也就是说,由于您可以同时拥有对变量的可变引用和不可变引用,因此当您将它们分别传递给同一函数时会导致大量问题,该函数假定不可变引用和可变引用是唯一的。阅读 Rust 文档中的 this page 了解更多相关信息。