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为我可以使用的字符串.我究竟做错了什么?
你正在混淆两个不同的过程.
首先是强制; 特别是Deref胁迫.当编译器发现你有一个&U,但你想要一个时,会发生这种情况&T.如果有impl Deref<Target=T> for U,它会为你做强制.这就是为什么一个人&String会强迫一个人&str.
但是,当编译器替换泛型类型参数时,这不起作用.当你说BigNum::new(&line),编译器看到的是你试图传递&String它所期望的地方S; 因此,S必须&String,因此S必须实施Into<String>......哦不!它没有! 繁荣! 强制从未被触发,因为编译器永远不需要强制任何东西; 未实现的类型约束是一个不同的问题.
在这种特殊情况下,你应该做什么取决于你的情况:
你可以通过String; 用line或line.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)