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?
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.
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?
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);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With