[英]the From<&String> trait is not implemented for the type String
I'm going off of this article in an attempt to write a function that accepts both a String and a &str, but I'm running into a problem. 我会掉这在试图写一个接受两个字符串和&STR功能的文章,但我遇到了一个问题。 I have the following function:
我有以下功能:
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
is a simple struct, the problem however is when I attempted to call this with a &collections::string::String
I get an error: 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);
I was under the impression that a &String
will be implicitly broken down into a &str
no? 我的印象是
&String
会被隐含地分解为&str
no? And in that case the Into
trait would convert the &str
into a String I could then use. 在这种情况下,
Into
trait会将&str
转换为我可以使用的String。 What am I doing wrong? 我究竟做错了什么?
You're conflating two different processes. 你正在混淆两个不同的过程。
First, there's coercion; 首先是强制; in particular,
Deref
coercion . 特别是
Deref
强制 。 This happens when the compiler sees that you have a &U
, but you want a &T
. 当编译器发现你有一个
&U
但你想要一个&T
时会发生这种情况。 Provided there is an impl Deref<Target=T> for U
, it will do the coercion for you. 如果
impl Deref<Target=T> for U
有一个impl Deref<Target=T> for U
,它会为你做强制。 This is why a &String
will coerce to a &str
. 这就是
&String
强制转换为&str
。
However , this does not come into play when the compiler is substituting generic type parameters. 但是 ,当编译器替换泛型类型参数时,这不起作用 。 When you say
BigNum::new(&line)
, what the compiler sees is that you're trying to pass a &String
where it expects an S
; 当你说
BigNum::new(&line)
,编译器看到的是你试图传递一个&String
,它需要一个S
; thus, S
must be &String
, thus S
must implement Into<String>
and... oh no! 因此,
S
必须是&String
,因此S
必须实现Into<String>
并且......哦不! It doesn't! 它没有! BOOM!
繁荣! Coercion is never triggered because the compiler never needs to coerce anything;
强制从未被触发,因为编译器永远不需要强制任何东西; unfulfilled type constraints are a different problem.
未实现的类型约束是一个不同的问题。
In this particular case, what you should do depends on your circumstances: 在这种特殊情况下,你应该做什么取决于你的情况:
You can just pass a String
; 你可以传递一个
String
; use line
or line.clone()
. 使用
line
或line.clone()
。 This is the most efficient in that you can always pass in an owned String
you no longer need and avoid an extra allocation. 这是最有效的,因为您始终可以传入不再需要的拥有
String
并避免额外分配。
You can instead take an &S
with S: ?Sized + AsRef<str>
, which doesn't allow you to pass an owned string, but if you're always going to allocate anyway, this may be more ergonomic. 您可以使用
S: ?Sized + AsRef<str>
取一个&S
,它不允许您传递一个拥有的字符串,但如果您总是要分配,那么这可能更符合人体工程学。
Here's an example of both in action: 以下是两个实际操作的示例:
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);
}
As mentioned by DK., this is not possible with the Rust Into
trait, because of the missing implementation of Into<String> for &String
. 正如DK所提到的,由于缺少
Into<String> for &String
的Into<String> for &String
实现,因此Rust Into
trait不可能实现这一点。 I couldn't find the reasons behind this, but you can create your own Trait to solve this: 我找不到这背后的原因,但你可以创建自己的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 }
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.