Hi,
i'm trying to get into Rust and thought of writing a linked list, which by now helped me a lot to dig into the language and its documentation.
My approach was creating two structs, a Node and a List Struct and maybe an own implementation of a list iterator, either using a struct or implementing the standard into_iter impl of Rust itself on the List and the Node struct.
To get to the point, i wrote an add function to create a node holding a i32 value and a pointer that should be able to reference to the next node, if a new node is created. To test this i needed to implement an iterator to print out the actual nodes, but that is were i get stuck.
I can iterate through the created linked list, where i implemented the into_iter() trait, but that just gives me the address where the linked list is created, which means, i also need to iterate through all dependent nodes in the linked list to actually get the i32 values contained in the nodes.
this is the code:
list.rs
use std::ptr::read;
use std::fmt::{ Display, Formatter, Result };
pub struct List {
head: *const Node
}
impl List {
pub fn new() -> Self {
List {
head: ptr::null()
}
}
pub fn add(&mut self, value: i32) {
if self.head == ptr::null() {
self.head = &Node::new(value);
return
}
let mut _ptr1 = self.head;
unsafe {
while (*_ptr1).next != ptr::null() {
_ptr1 = (*_ptr1).next;
}
}
let mut _ptr2 = Node::new(value);
unsafe {
read(_ptr1).next = &_ptr2;
}
}
}
impl Display for List {
fn fmt(&self, f: &mut Formatter) -> Result {
write!(f, "List: {}", self)
}
}
pub struct Node {
value: i32,
next: *const Node
}
impl Node {
pub fn new(val: i32) -> Self {
Node {
value: val,
next: ptr::null()
}
}
}
impl IntoIterator for List {
type Item = *const Node;
type IntoIter = ListIntoIterator;
fn into_iter(self) -> Self::IntoIter {
ListIntoIterator { list: self, index: 0 }
}
}
pub struct ListIntoIterator {
list: List,
index: usize,
}
impl Iterator for ListIntoIterator {
type Item = *const Node;
fn next(&mut self) -> Option<Self::Item> {
let result = match self.index {
0 => self.list.head, // List 1
// {
// for node in self.list.head.into_iter() {
// return node.value;
// }
// },
1 => self.list.head,
// 2 => self.list.head,
_ => return None,
};
self.index += 1;
Some(result)
}
}
impl IntoIterator for Node {
type Item = i32;
type IntoIter = NodeIntoIterator;
fn into_iter(self) -> Self::IntoIter {
NodeIntoIterator { node: &self, index: 0 }
}
}
pub struct NodeIntoIterator {
node: *const Node,
index: usize,
}
impl Iterator for NodeIntoIterator {
type Item = i32;
fn next(&mut self) -> Option<i32> {
unsafe{
let result = match self.index {
0 => (*self.node).value, // Node 1
1 => (*self.node).value, // Node 2
2 => (*self.node).value, // Node 3
_ => return None,
};
self.index += 1;
Some(result)
}
}
}
impl Display for Node {
fn fmt(&self, f: &mut Formatter) -> Result {
write!(f, "Node: {}", self)
}
}
main.rs
pub mod list;
use list::List;
fn main() {
let mut list1 = List::new();
list1.add(3);
list1.add(6);
// let mut list2 = List::new();
for _i in list1.into_iter() {
println!("{:?}", &_i);
// for j in _i.into_iter() {
// println!("{}", j);
// }
};
}
What can i do to make this work? Also, how can i improve this code? ( e.g.: am i using unsafe where i shouldn't or do i have to implement a list iterator myself to make this work more properly by using raw pointers?)
i hope this is a legit thread and not too much to ask, but i'd be glad for any help to make this implementation of the linked list work.
kind regards,
Timo