如何在Rust中将Vec <String>和Vec <str>都接受为函数arg

时间:2019-07-26 16:01:03

标签: string generics vector rust

我正在开发我的第一个Rust板条箱,我想通过同时允许foo(vec!["bar", "baz"])foo(vec![String::from("foo"), String::from("baz")])使我的API更加用户友好。

到目前为止,我已经设法接受了String&str,但是我一直在努力为Vec<T>做同样的事情。

fn foo<S: Into<String>>(string: S) -> String {
    string.into()
}

fn foo_many<S: Into<String>>(strings: Vec<S>) -> Vec<String> {
    strings.iter().map(|s| s.into()).collect()
}

fn main() {
    println!("{}", foo(String::from("bar")));
    println!("{}", foo("baz"));

    for string in foo_many(vec!["foo", "bar"]) {
        println!("{}", string);
    }
}

我得到的编译器错误是:

error[E0277]: the trait bound `std::string::String: std::convert::From<&S>` is not satisfied
 --> src/main.rs:6:30
  |
6 |     strings.iter().map(|s| s.into()).collect()
  |                              ^^^^ the trait `std::convert::From<&S>` is not implemented for `std::string::String`
  |
  = help: consider adding a `where std::string::String: std::convert::From<&S>` bound
  = note: required because of the requirements on the impl of `std::convert::Into<std::string::String>` for `&S`

2 个答案:

答案 0 :(得分:4)

这不起作用,因为您的迭代没有给您S,而是&S

如果要字符串从向量中移出,则必须使其可变并耗尽:

fn foo_many<S: Into<String>>(mut strings: Vec<S>) -> Vec<String> {
    strings.drain(..).map(|s| s.into()).collect()
}

playground

答案 1 :(得分:4)

您可以使用完全泛型,而不必强迫用户使用Vec,更好的是,您可以采用实现IntoIterator的泛型类型,而只需编写{{ 1}}实现Into<String>,其语法有些奇怪且逻辑合理。您需要第二个通用类型来执行此操作。我将Item称为迭代器,将T称为Item类型。

I

这解决了您的问题,并使您的功能更加通用。