简体   繁体   English

Rustlings 练习 Traits2,在 Vec 上实现 Trait

[英]Rustlings Exercise Traits2, Implement Trait on Vec

The exercise requires me to Implement the trait to Vec.该练习要求我将特征实现到 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, Vec is another story.我已经完成了 String 的 trait 实现,这很简单,Vec 是另一回事。 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 atempt.我正在提供原始代码、我的尝试以及我尝试时遇到的错误。 Hopefull that will be enough.希望这就足够了。

Original Code from the Rustlings repo : 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"));
    }

}

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's a discrepancy to Aloso's answer. Aloso 的回答有出入。 Andre gives it too.安德烈也给了。

When you take in self :当你接受self

fn append_bar(self) -> Self {
    self.push("Bar".to_owned());
    self
}

You are taking in a mutable Vec :你正在接受一个可变的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.即使变量foo被声明为可变的,方法append_bar()接受一个不可变的变量。 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.您不需要借用self因为您不是试图获得全部所有权,而是试图修改驻留在所述变量中的现有数据。 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 String s and return it with the appended string.append_bar()的范围内,您试图改变String的集合并将其与附加的字符串一起返回。

There are several issues:有几个问题:

  • You try to push a String to generic Vec<T> , where T can be any type!您尝试将String推送到泛型Vec<T> ,其中T可以是任何类型!
  • The method signature is different from the assignment: Your method is defined as方法签名与赋值不同:您的方法定义为
    fn append_bar(&mut self) -> Self
    but it should be但应该是
    fn append_bar(self) -> Self
  • You try to return the result of Vec::push , but this method doesn't return anything.您尝试返回Vec::push的结果,但此方法不返回任何内容。

To fix the first issue, implement the trait for Vec<String> instead of Vec<T> .要解决第一个问题,请为Vec<String>而不是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:要解决最后一个问题,请在单独的语句中调用Vec::push后返回self

self.push(bar);
self

Thanks to @Aloso for help and Jussi too i managed to get the example working.感谢@Aloso 和 Jussi 的帮助,我设法使示例正常工作。

Mutation was needed in order to compile, so i ended up with code that compiles as follows:为了编译需要突变,所以我最终得到了编译如下的代码:


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

I believe the correct answer for this problem shall look like this:我相信这个问题的正确答案应该是这样的:

trait AppendBar {
    fn append_bar(self) -> Self;
}

impl AppendBar for Vec<String> {
    fn append_bar(mut self) -> Self {
        self.push("Bar".to_string());
        self
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM