如何在 Vec 上实现可以附加字符串的特征?

问题描述 投票:0回答:4

这是来自尝试 Rustlings 运动特征 2。该练习要求我在

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`.

我已经阅读并重新阅读了书中的建议部分和特征,但它超出了我的范围。我确信这是一个简单的解决方案,但我看不到它。

rust vector traits
4个回答
3
投票

有几个问题:

  • 您尝试将
    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.

要解决第二个问题,您必须删除

&
,因此该方法接受 owned 值。

要解决最后一个问题,请在单独的语句中调用

self
后返回
Vec::push

self.push(bar);
self

3
投票

Aloso 的答案存在差异。安德烈也给了。

当你接受

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
被声明为可变的,方法
append_bar()
也接受一个不可变的变量。您不需要借用
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
的集合并使用附加字符串返回它。


2
投票

我相信这个问题的正确答案应该是这样的:

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

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


0
投票

感谢@Aloso 的帮助和Jussi,我成功地让这个例子工作了。

为了编译需要进行突变,所以我最终得到了编译如下的代码:


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

© www.soinside.com 2019 - 2024. All rights reserved.