Using Rust Trait AsRef along with Generic Data Type
- Quiz
- Tips
- Example answer
- Follow-up: Why
bit_iter
is read only while thenext()
need&mut self
- Follow-up: Can I modify the data during iterator
- Follow-up: Why not use
From
Trait?
The Rust Trait is one of my most favor features in Rust and also the biggest obstacle I faced during my rust learning path. Whenever I fell I have mastered it by reading Rust books and blogs, the compiler still politely remind me the opposite with flooding errors.
So let’s learn it in a complex way through a coding quiz.
Quiz
Providing main.rs
with this content:
|
|
Please implement BitIterator
in bit_iterator.rs
counting the position
of bit set to 1.
The expected output is
Got bit 0 set to 1
Got bit 9 set to 1
Got bit 18 set to 1
Got bit 27 set to 1
Tips
IntoIterator
and Iterator
Trait
The for loop is actually a syntax sugar using IntoIterator
trait.
And the rust doc for iterator mentioned the IntoIterator
is automatically implement if your data type has implemented Iterator
:
|
|
Our task is pretty clear now: implement std::iter::Iterator with:
type Item
indicate the return data type on each iteration.fn next() -> Option<Self::Item>
to iterate. None will stop the iteration.
Generic Data Type and AsRef
Trait
The BitIterator::new()
is taking a reference, if we are storing it
into struct BitIterator
, we need to define its lifetime which is another
nightmare for rust new learner.
Let avoid it by using AsRef
and generic data type T
(It does not have to be
named as T
, just a convention) like:
|
|
With that, we can use let data: &[u8] = self.data.as_ref()
to access the
data to search bits.
You can implement the Iterator Trait like:
|
|
With everything you required mentioned above, please stop the reading and code the quiz out. Try to understand compiler errors during coding and seek for help from search engine, or other developers.
Example answer
|
|
I believe the code is transparent, but I would like to bring up some questions to dive deep into this topic.
Follow-up: Why bit_iter
is read only while the next()
need &mut self
The for
loop is syntax sugar, meaning this for pos in bit_iter
is actually
looks like(not real compiler de-sugar code):
|
|
The IntoIterator::into_iter()
took the ownership and change it to mut
.
Follow-up: Can I modify the data during iterator
You may try to compile this:
|
|
The compiler will stop you with
cannot borrow `a` as mutable because it is also borrowed as immutable.
If you want to modify it, please store the pending changes and modify it after the iterator drooped, for example:
|
|
Follow-up: Why not use From
Trait?
Instead of data.as_ref()
, we can also use let data: &[u8] = data.into()
which still works well.
Both AsRef
and From
can convert one data type to another. But the AsRef
trait is designed for cheap reference-to-reference
while the From
trait is
targeted for costly conversion. In our case Vec<u8>
to &[u8]
is a cheap
reference-to-reference conversion.
Meanwhile, many rust native data type as AsRef<[u8]>
implemented, but no
Into<[u8]>
. Using AsRef
allowing our iterator support more data types
out of box.
Hence, AsRef()
is preferred here.