Черты упражнения Шорох2, Реализовать черту на Vec
Это упражнение требует от меня реализовать черту Vec. Тесты уже есть, но они не работают, и это хорошее место для начала. Я сделал реализацию трейта для String, и это было легко, Vec - совсем другая история. Я не уверен, что метод должен вернуть, он не работает при различных возвратах. Я предоставляю исходный код, свою попытку и ошибки, которые я получаю за свою попытку. Надеюсь, этого будет достаточно.
Исходный код из репозитория Rustlings:
// 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"));
}
}
и моя попытка решить эту проблему:
// 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"));
}
}
Что компилируется с ошибкой:
! 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`.
Я прочитал и перечитал предложенную часть и особенности книги, но это выше меня. Я уверен, что это простое решение, но я этого не вижу.
4 ответа
Есть несколько проблем:
- Вы пытаетесь подтолкнуть
String
к общемуVec<T>
, гдеT
может быть любым! - Подпись метода отличается от присвоения: ваш метод определяется как
но это должно бытьfn append_bar(&mut self) -> Self
fn append_bar(self) -> Self
- Вы пытаетесь вернуть результат
Vec::push
, но этот метод ничего не возвращает.
Чтобы исправить первую проблему, реализуйте трейт для Vec<String>
вместо того Vec<T>
. Вот чего требует задание:
// Your task is to implement the trait // `AppendBar' for a vector of strings.
Чтобы исправить вторую проблему, вам нужно удалить &
, поэтому метод принимает собственное значение.
Чтобы исправить последнюю проблему, верните self
после звонка Vec::push
в отдельном заявлении:
self.push(bar);
self
В ответе Алосо есть несоответствие. Андре тоже дает.
Когда вы принимаете:
fn append_bar(self) -> Self {
self.push("Bar".to_owned());
self
}
Вы принимаете изменчивый
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"));
Несмотря на то, что переменная
foo
объявляется изменяемым, метод принимает неизменяемую переменную. Вам не нужно брать взаймы
self
поскольку вы не пытаетесь получить полное право собственности, вы пытаетесь изменить существующие данные, находящиеся в указанной переменной. Правильный ответ
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
}
В рамках
append_bar()
вы пытаетесь изменить коллекцию
String
s и верните его с добавленной строкой.
Я считаю, что правильный ответ на эту проблему будет выглядеть так:
trait AppendBar {
fn append_bar(self) -> Self;
}
impl AppendBar for Vec<String> {
fn append_bar(mut self) -> Self {
self.push("Bar".to_string());
self
}
}
Благодаря @Aloso за помощь и Юсси мне удалось заставить пример работать.
Для компиляции потребовалась мутация, поэтому я получил код, который компилируется следующим образом:
// 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(&mut self) -> Self;
}
//TODO: Add your code here
impl AppendBar for Vec<String> {
fn append_bar(&mut self) -> Self {
self.push(String::from("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"));
}
}