リンクされたリストを実装しているときに、生のポインターを学習するのに苦労しています。単純なコードで意図しない結果が得られ、その説明を見つけるのに苦労しています。
use std::cmp::PartialEq;
use std::default::Default;
use std::ptr;
pub struct LinkedListElement<T> {
pub data: T,
pub next: *mut LinkedListElement<T>,
}
pub struct LinkedList<T> {
head: *mut LinkedListElement<T>,
}
impl<T: PartialEq> LinkedListElement<T> {
pub fn new(elem: T, next: Option<*mut LinkedListElement<T>>) -> LinkedListElement<T> {
let mut_ptr = match next {
Some(t) => t,
None => ptr::null_mut(),
};
let new_elem = LinkedListElement {
data: elem,
next: mut_ptr,
};
if !mut_ptr.is_null() {
println!(
"post create ll mut ptr: {:p}, post create ll mut ptr next {:p}",
mut_ptr,
unsafe { (*mut_ptr).next }
);
}
new_elem
}
}
impl<T: PartialEq + Default> LinkedList<T> {
pub fn new(elem: T) -> LinkedList<T> {
LinkedList {
head: &mut LinkedListElement::new(elem, None),
}
}
pub fn insert(&mut self, elem: T) {
println!("head: {:p} . next: {:p}", self.head, unsafe {
(*self.head).next
});
let next = Some(self.head);
let mut ll_elem = LinkedListElement::new(elem, next);
println!(
"before pointer head: {:p}. before pointer next {:p}",
self.head,
unsafe { (*self.head).next }
);
let ll_elem_ptr = &mut ll_elem as *mut LinkedListElement<T>;
self.head = ll_elem_ptr;
}
}
fn main() {
let elem: i32 = 32;
let second_elem: i32 = 64;
let third_elem: i32 = 72;
let mut list = LinkedList::new(elem);
list.insert(second_elem);
list.insert(third_elem);
}
(遊び場)
このコードにより、次の出力が得られます。
head: 0x7ffe163275e8 . next: 0x0
post create ll mut ptr: 0x7ffe163275e8, post create ll mut ptr next 0x0
before pointer head: 0x7ffe163275e8. before pointer next 0x0
head: 0x7ffe16327560 . next: 0x7ffe163275e8
post create ll mut ptr: 0x7ffe16327560, post create ll mut ptr next 0x7ffe163275e8
before pointer head: 0x7ffe16327560. before pointer next 0x7ffe16327560
最初の 2 つの要素では、コードは期待どおりに動作します。次の要素として null ポインターを持つ要素を作成します。2 番目の要素を追加した後の状態は次のとおりです。
{
head: {
elem: 64,
next: {
elem: 32,
next: nullptr
}
}
}
64 -> 32 -> null
3 番目の要素が追加されると、事態はおかしくなり、リンクされたリストは次のように変換されます。
{
head: {
elem: 72,
next: {
elem: 72,
next: {
elem: 72,
next: ...
}
}
}
}
72 -> 72 -> 72 -> ...
リンクされたリスト要素のnext
フィールドが要素自体を指し始めているようです。
メソッドをデバッグしたLinkedListElement::new
ところ、適切な要素が返されるはずであることがわかりました。
{
elem: 72,
next: {
elem: 64,
next: {
elem: 32,
next: nullptr
}
}
}
LinkedList::insert
メソッドに戻された直後、self.head
再代入前でもなぜか中身LinkedList
self
が「壊れた」状態になってしまう。
Rust で生のポインターを使用することは慣用的ではないことはわかっていますが、それでも学びたいと思っています。