没有为String类型实现From <&String>特征

Syn*_*ose 6 string ownership rust

我会掉在试图写一个接受两个字符串和&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 }
}
Run Code Online (Sandbox Code Playgroud)

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

let line = "123456".to_string()
let big = bignum::BigNum::new(&line)
Run Code Online (Sandbox Code Playgroud)
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);
Run Code Online (Sandbox Code Playgroud)

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

DK.*_*DK. 7

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

首先是强制; 特别是Deref胁迫.当编译器发现你有一个&U,但你想要一个时,会发生这种情况&T.如果有impl Deref<Target=T> for U,它会为你做强制.这就是为什么一个人&String会强迫一个人&str.

但是,当编译器替换泛型类型参数时,这不起作用.当你说BigNum::new(&line),编译器看到的是你试图传递&String它所期望的地方S; 因此,S必须&String,因此S必须实施Into<String>......哦不!它没有! 繁荣! 强制从未被触发,因为编译器永远不需要强制任何东西; 未实现的类型约束是一个不同的问题.

在这种特殊情况下,你应该做什么取决于你的情况:

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

  • 你可以改为使用&Swith S: ?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);
}
Run Code Online (Sandbox Code Playgroud)