How to implement types like linked lists that can have circular references
Hello my friend,Thank you very much for creating this project. I am currently working on a project where Rust calls Go, and I'm planning to use your project for this purpose. However, my Go struct is a type that can have circular references, similar to a linked list, like:
type Node struct {
Value int
Next *Node
}
I initially implemented this in Rust as:
#[derive(rust2go::R2G, Clone)]
pub struct Node {
elem: i32,
next: Option<Rc<Node>>,
}
But I found that it doesn't work. Later, I attempted to use raw pointers to resolve the issue:
#[derive(rust2go::R2G, Clone)]
pub struct Node {
elem: i32,
next: *mut Node,
}
I'm still encountering errors.
Additionally, is it also impossible to generate a Map?
#[derive(rust2go::R2G, Clone)]
pub struct MapTest {
elem: HashMap<String, String>,
}
Could you please help me with this issue? Thank you.
Linked list is almost the hardest data structure in Rust because some unsafe pointer operations are not allowed. You can refer to this tutorial to see if it can help: https://rust-unofficial.github.io/too-many-lists/
For the HashMap, a key-value pair type can be helpful:
#[derive(rust2go::R2G, Clone)]
pub struct KeyValuePair {
key: String,
value: String,
}
#[derive(rust2go::R2G, Clone)]
pub struct MapTest {
elem: Vec<KeyValuePair>,
}
@lirenjie95 Yes, implementing linked lists is a very challenging task in Rust, so I want to use raw pointers to simplify the problem. I plan to implement the logic for next in my own Rust code.
#[derive(rust2go::R2G, Clone)]
pub struct Node {
elem: i32,
next: *mut Node,
}
impl Node {
pub fn new(elem: i32) -> Self {
Node {
elem,
next: std::ptr::null_mut(),
}
}
pub fn set_next(&mut self, next: Option<&mut Node>) {
self.next = next.map_or(std::ptr::null_mut(), |n| n as *mut Node);
}
pub unsafe fn next_mut(&mut self) -> Option<&mut Node> {
if self.next.is_null() {
None
} else {
Some(&mut *self.next)
}
}
pub unsafe fn next(&self) -> Option<&Node> {
if self.next.is_null() {
None
} else {
Some(&*self.next)
}
}
pub fn elem(&self) -> i32 {
self.elem
}
pub fn elem_mut(&mut self) -> &mut i32 {
&mut self.elem
}
pub fn next_ptr(&self) -> *mut Node {
self.next
}
}
This corresponds exactly to the Go version:
type Node struct {
Value int
Next *Node
}
I am curious if this kind of implementation poses any difficulties, or if it's inherently unsupported by your project's design. Additionally, the map structure I described earlier was too simplistic. In reality, my map should look like this:
#[derive(rust2go::R2G, Clone)]
pub struct KeyValuePair {
key: String,
value: Node,
}
#[derive(rust2go::R2G, Clone)]
pub struct MapTest {
elem: Vec<KeyValuePair>,
}
Could you please let me know if these scenarios are considered for support in your project?
In theory it should be supported. I can't remember if the current implementation can handle it correctly.
rust2go has a topological sorting logic when generating code. If it does not currently support self-reference, then the relevant code may need to be optimized.