Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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. 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:

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? And in that case the Into trait would convert the &str into a String I could then use. What am I doing wrong?

like image 267
Syntactic Fructose Avatar asked Jul 18 '15 14:07

Syntactic Fructose


People also ask

Where is the series from filmed?

Where was From on Epix filmed? From was filmed in the Canadian province of Nova Scotia. The project was filmed there entirely but is set in middle America.

Is there going to be a season 2 of from?

Together, they must find a way to keep their children — Julie (Cheramy) and Ethan (Webster) — safe as they desperately search for a way back home. From has been renewed for a second season which will debut (TBD 2023). Stay tuned for further updates. Want to automatically receive updates about this TV show?


1 Answers

You're conflating two different processes.

First, there's coercion; in particular, Deref coercion. This happens when the compiler sees that you have a &U, but you want a &T. Provided there is an impl Deref<Target=T> for U, it will do the coercion for you. This is why a &String will coerce to a &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; thus, S must be &String, thus S must implement Into<String> and... oh no! 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; use line or 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.

  • 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.

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);
}
like image 153
DK. Avatar answered Oct 23 '22 11:10

DK.