From<& String>字符串

时间:2015-07-18 14:48:03

标签: string rust ownership

我要离开this文章试图编写一个接受字符串和& str的函数,但我遇到了问题。我有以下功能:

pub fn new<S>(t_num: S) -> BigNum where S: Into<String> {
    let t_value = t_num.into();
    let t_digits = t_value.len();
    BigNum { value: t_value, digits: t_digits }
}

BigNum是一个简单的结构,但问题是,当我尝试用&collections::string::String调用它时,我收到错误:

let line = "123456".to_string()
let big = bignum::BigNum::new(&line)
main.rs:23:15: 23:34 error: the trait `core::convert::From<&collections::string::String>` is not implemented for the type `collections::string::String` [E0277]
main.rs:23     let big = bignum::BigNum::new(&line);

我的印象是,&String会被隐含地分解为&str否?在这种情况下,Into特征会将&str转换为我可以使用的字符串。我做错了什么?

2 个答案:

答案 0 :(得分:6)

你正在混淆两个不同的过程。

首先,有强制;尤其是Deref coercion。当编译器发现您有&U,但想要 &T时会发生这种情况。如果有impl Deref<Target=T> for U,它会为你做强制。这就是&String强制转换为&str

的原因

然而,当编译器替换泛型类型参数时,此不会发挥作用。当你说BigNum::new(&line)时,编译器看到的是你试图传递&String所需的S;因此,S必须为&String,因此S必须实施Into<String>并且......哦不!它没有! BOOM!强制从未被触发,因为编译器永远不会需要来强制执行任何操作;未实现的类型约束是一个不同的问题。

特定的案例中,您应该做什么取决于您的具体情况:

  • 你可以传递String;使用lineline.clone()。这是最有效的,因为您可以随时传入您不再需要的拥有String并避免额外分配。

  • 您可以使用&SS: ?Sized + AsRef<str>,但不允许您传递拥有的字符串,但如果您总是要分配,则可能更多符合人体工程学。

以下是两者的实例:

use std::convert::AsRef;

fn main() {
    take_a_string(String::from("abc"));
    // take_a_string(&String::from("abc")); // Boom!
    take_a_string("def");

    // take_a_string_ref(String::from("abc")); // Boom!
    take_a_string_ref(&String::from("abc"));
    take_a_string_ref("def");
}

fn take_a_string<S>(s: S)
where S: Into<String> {
    let s: String = s.into();
    println!("{:?}", s);
}

fn take_a_string_ref<S: ?Sized>(s: &S)
where S: AsRef<str> {
    let s: String = s.as_ref().into();
    println!("{:?}", s);
}

答案 1 :(得分:0)

正如DK。所提到的,由于缺少Into的实现,因此使用Rust Into<String> for &String特征是不可能的。我找不到背后的原因,但是您可以创建自己的Trait来解决此问题:

pub trait IntoString {
    fn into(self) -> String;
}

impl IntoString for &String {
    fn into(self) -> String {
        self.to_string()
    }
}
impl IntoString for &str {
    fn into(self) -> String {
        self.to_string()
    }
}

impl IntoString for String {
    fn into(self) -> String {
        self
    }
}

pub fn new<S>(t_num: S) -> BigNum where S: IntoString {
    let t_value = t_num.into();
    let t_digits = t_value.len();
    BigNum { value: t_value, digits: t_digits }
}