Implementing functionality for types with generic type parameters

If we want to have functions that are part of a type with generic type parameters, we need to have an implementation block, the same as if the type didn't have those parameters, but we need to parameterize the implementation block, too.

Here is the beginning of our implementation block for the TreeNode type:

impl<K, V> TreeNode<K, V> where K: PartialOrd + PartialEq {

Now, TreeNode<K, V> is the data type we're implementing functionality for. It's the impl<K, V> part that tells the compiler that K and V are generic type parameters, and it's K: PartialOrd + PartialEq that tells it the trait bounds for those parameters. It does not just use the same generic type parameters and trait bounds that were specified for the data type, because implementation blocks are allowed to differ from the data type; for example, there's an implementation block for Box<Any> that provides the downcast function for a boxed Any, which is not a part of Box under other circumstances. If the implementation block's trait bounds match what is actually being using for type parameters, the functions in the block are available. If they do not, the functions are not available.

Inside the implementation block, we can use K and V as the names of data types:

    fn set(&mut self, key: K, value: V) {
if key == self.key {
self.value = value;
}
else if key < self.key {
match self.lesser {
None => {
self.lesser = Some(
Box::new(TreeNode {key, value, lesser: None,
greater: None })
);
},
Some(ref mut lesser) => {
lesser.set(key, value);
}
}
}
else {
match self.greater {
None => {
self.greater = Some(
Box::new(TreeNode {key, value, lesser: None,
greater: None })
);
}
Some(ref mut greater) => {
greater.set(key, value);
}
}
}
}

Here we have the code to associate a key with a value inside our binary tree. It starts off with a pretty standard function definition, except that we're using K and V to specify the data types of the key and value parameters. We mutably borrow self because setting a contained value is a mutation.

Inside the function, we first compare the current node's key to the key we're looking for, and if they're the same, we just assign the value to the current node.

Next, we check whether the key we're looking for is less than or greater than the current node's key, and use that to select which branch of the tree to travel down. Either way, we use a match expression to figure out whether there actually is a branch on that side, and if there's not, we create one containing the specified key and value. If there is a branch on that side, we call that node's set function, which does the same thing all over again except with a different self.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.186.178