This is from trying Rustlings Exercise Traits2. The exercise requires me to implement the trait on a Vec. The tests are there and they are failing, which is a good place to start. I've done the trait implementation for the String and it was easy, but Vec is another story. I'm not sure what the method needs to return, it fails on various returns. I'm providing original code, my attempt and the errors i get for my attempt. Hopefully that will be enough.
Original Code from the Rustlings repo:
// traits2.rs
//
// Your task is to implement the trait
// `AppendBar' for a vector of strings.
//
// To implement this trait, consider for
// a moment what it means to 'append "Bar"'
// to a vector of strings.
//
// No boiler plate code this time,
// you can do this!
// I AM NOT DONE
trait AppendBar {
fn append_bar(self) -> Self;
}
//TODO: Add your code here
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn is_vec_pop_eq_bar() {
let mut foo = vec![String::from("Foo")].append_bar();
assert_eq!(foo.pop().unwrap(), String::from("Bar"));
assert_eq!(foo.pop().unwrap(), String::from("Foo"));
}
}
and my attempt to solve it:
// traits2.rs
//
// Your task is to implement the trait
// `AppendBar' for a vector of strings.
//
// To implement this trait, consider for
// a moment what it means to 'append "Bar"'
// to a vector of strings.
//
// No boiler plate code this time,
// you can do this!
// I AM NOT DONE
use std::clone::Clone;
trait AppendBar {
fn append_bar(&mut self) -> Self;
}
//TODO: Add your code here
impl<T: Clone> AppendBar for Vec<T> {
fn append_bar(&mut self) -> Self {
let bar: T = String::from("Bar");
self.to_vec().push(bar)
// self.to_vec()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn is_vec_pop_eq_bar() {
let mut foo = vec![String::from("Foo")].append_bar();
assert_eq!(foo, vec![String::from("Foo"), String::from("Bar")]);
assert_eq!(foo.pop().unwrap(), String::from("Bar"));
assert_eq!(foo.pop().unwrap(), String::from("Foo"));
}
}
Which compiles to an error:
! Compiling of exercises/traits/traits2.rs failed! Please try again. Here's the output:
error[E0308]: mismatched types
--> exercises/traits/traits2.rs:22:22
|
20 | impl<T: Clone> AppendBar for Vec<T> {
| - this type parameter
21 | fn append_bar(&mut self) -> Self {
22 | let bar: T = String::from("Bar");
| - ^^^^^^^^^^^^^^^^^^^ expected type parameter `T`, found struct `std::string::String`
| |
| expected due to this
|
= note: expected type parameter `T`
found struct `std::string::String`
= help: type parameters must be constrained to match other types
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
error[E0308]: mismatched types
--> exercises/traits/traits2.rs:23:9
|
21 | fn append_bar(&mut self) -> Self {
| ---- expected `std::vec::Vec<T>` because of return type
22 | let bar: T = String::from("Bar");
23 | self.to_vec().push(bar)
| ^^^^^^^^^^^^^^^^^^^^^^^ expected struct `std::vec::Vec`, found `()`
|
= note: expected struct `std::vec::Vec<T>`
found unit type `()`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.
I've read and re-read the suggested part and the traits in the book but it's beyond me. I'm sure it's a simple solution to it but i can't see it.
There are several issues:
String to generic Vec<T>, where T can be any type!fn append_bar(&mut self) -> Self
but it should be
fn append_bar(self) -> Self
Vec::push, but this method doesn't return anything.To fix the first issue, implement the trait for Vec<String> instead of Vec<T>. That's what the assignment is asking for:
// Your task is to implement the trait // `AppendBar' for a vector of strings.
To fix the second issue, you have to remove the &, so the method accepts an owned value.
To fix the last issue, return self after calling Vec::push in a separate statement:
self.push(bar);
self
There's a discrepancy to Aloso's answer. Andre gives it too.
When you take in self:
fn append_bar(self) -> Self {
self.push("Bar".to_owned());
self
}
You are taking in a mutable Vec:
let mut foo = vec![String::from("Foo")].append_bar();
assert_eq!(foo.pop().unwrap(), String::from("Bar"));
assert_eq!(foo.pop().unwrap(), String::from("Foo"));
Even though the Variable foo is declared to be mutable, the method append_bar() takes in a immutable variable. You don't need to borrow self because you're not trying to take full ownership, you're trying to modify the existing data residing in said variable. The correct answer is
fn append_bar(mut self) -> Self {
self.push("Bar".to_owned()); // || .to_string() || String::from("Bar")
// Whatever gets the point across. As the String literal is essentially a "Borrowed" string.
self
}
Within the scope of append_bar() you're trying to mutate the collection of Strings and return it with the appended string.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With