The Vec::<T>::get()
method returns an Option<&T>
, that is, an option of a reference into the vector. Because your vector already contains references (&str
), it means that get()
in your case returns Option<&&str>
.
Now, the reason why your first example compiles is that by being explicit about the type of the s
variable you cause deref coercion to fire, that is, the compiler will automatically insert a dereference operator:
// You write this:
let s: &str = v.get(0).unwrap();
// Compiler actually does this:
let s: &str = *v.get(0).unwrap();
Then, because there exists an implementation of the From<&str>
trait for String
, the compiler accepts the String::from(s)
call.
In the second piece, however, without an explicit type annotation the type assigned to s
is &&str
:
let s: &&str = v.get(0).unwrap();
This changes the situation with the String::from()
method: there is no From<&&str>
implementation for String
, and the compiler fails to compile the code.
A logical question here would be why no deref coercion happens in this case, when s
is used as an argument for from()
? The answer is that deref coercion does not happen for generic methods, and String::from
is a generic method because it relies on the type parameter of the From
trait. The compiler can't do a deref coercion, because it is totally possible (in principle) to have both From<&str>
and From<&&str>
methods which would potentially do different things.
Even if From<&&str>
does not exist now, and the compiler would have applied a deref coercion, it would make the code brittle against future evolution: if for some reason From<&&str>
is added in a future version of the standard library, your code may silently break, because it will now call a different method than before, with potentially different logic.
(Naturally, I'm not saying that From<&&str>
would indeed be added in the future libstd version; this is generic reasoning applicable to any kind of trait, in any code base).