Черты упражнения Шорох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()вы пытаетесь изменить коллекцию Strings и верните его с добавленной строкой.

Я считаю, что правильный ответ на эту проблему будет выглядеть так:

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"));
    }
}

Другие вопросы по тегам