简体   繁体   English

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

[英]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() . 使用lineline.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 &StringInto<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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM