I'm attempting to implement the Default
trait for the struct BSTVars
. Below is what I have so far:
use std::collections::HashSet as HashSet;
use std::default::Default as Default;
use std::option::Option as Option;
pub struct Node<'node, T> {
value: T,
left: &'node Node<'node, T>,
right: &'node Node<'node, T>
}
pub struct BSTVars<'bstvars, T> {
pub root: &'bstvars Node<'bstvars, T>,
pub name: String,
pub count: i64
}
impl<T> Default for BSTVars<'_, T> {
fn default() -> Self {
BSTVars<T> {root: None, name: String::new(), count: 0}
}
}
pub trait BSTMethods<T> {
fn insert(&self, value: T);
fn find(&self, value: T);
fn remove(&self, value: T);
}
However, I am using RustRover, and it tells me there is an error with BSTVars<T> {root: None, name: String::new(), count: 0}
, specifically that it cannot find BSTVars
in this scope. I'm new to Rust, so does anyone have any ideas as to why this might be happening?
Okay so first of all, the reason you're getting that error is because Rust requires special syntax if you want to supply generic arguments in expression context. So that is, you can't write BSTVars<T> { /* fields */ }
because in expression context, the characters <
and >
are always interpreted as less than and greater than. In order to tell Rust you wanted generic arguments, you have to use the turbofish ::<>
, like this: BSTVars::<T> { /* fields */ }
. However, you actually would not need to provide the generic argument at all here, because Rust can usually infer it from context. Therefore, BSTVars { /* fields */ }
should be fine.
I also see several other issues with this code snippet, though, so lets go through them all.
Least significantly, Rust naming conventions dictate that initialisms such as BST should have only the first letter capitalized, so to follow the convention, it should be BstVars
and I will write it this way.
A major issue with the way you have laid out these types is that you're using references and lifetimes everywhere. References imply that this value is not owned and is merely being borrowed by your type. So if your nodes don't own their child nodes, then who does? Where are they being borrowed from? This kind of structure is better served by using boxes instead of references. Unlike &T , Box<T> owns its contents, this means we don't have to worry about lifetimes and since you're building a tree, every node being owned uniquely by its parent just makes sense. Additionally, if you want to be able to store None
in a variable, that variable must be an Option
. Unlike in other languages where any variable can be null
, all rust variables must be an actual instance. Thus, the type Option<T>
can be either Some(T)
or None
, allowing us to have a variable that might have nothing in it.
Another thing that seems a little strange is that you have created a trait called BstMethods
. Are you planning on having multiple different types that implement this trait? It seems to me that you really just want a single type called Bst
instead of separate BstVars
and BstMethods
.
Applying all of these changes, we have:
pub struct Node<T> {
value: T,
left: Option<Box<Node<T>>>,
right: Option<Box<Node<T>>>,
}
pub struct Bst<T> {
pub root: Option<Box<Node<T>>>,
pub name: String,
pub count: i64
}
impl<T> Default for Bst<T> {
fn default() -> Self {
Self {
root: None,
name: String::new(),
count: 0,
}
}
}
impl<T> Bst<T> {
fn insert(&self, value: T) {
todo!()
}
fn find(&self, value: T) {
todo!()
}
fn remove(&self, value: T) {
todo!()
}
}