Using generic trait methods like .into() when type inference is impossible
Solution 1
You could use From::from
:
use std::convert::*;
struct NewType(pub i32);
impl From<NewType> for i32 {
fn from(src: NewType) -> i32 {
src.0
}
}
fn main() {
let a = NewType(5);
println!("{}", i32::from(a));
}
You can read more about it in the docs for the convert
module.
Solution 2
I don't think there is a better way. Since the type parameter is on the trait, not the method into()
, the turbofish operator into::<i32>()
doesn't work. As you said, you can make it work by using the fully-qualified-syntax:
Into::<i32>::into(a)
Note, that Into
is reexported in std::prelude
, which means that you never have to specify the full path, as the trait is always in scope.
Of course, there is also always the possibility to bind your temporary to a name and use the type annotation of the let
-binding:
let tmp: i32 = a.into();
It might be better in the future, though! There is an Type Ascription for Expressions RFC, which was already accepted and implemented. The feature is still unstable, but if it's implemented you could write something like:
println!("{}", (a.into(): i32)); // still unstable :/
Solution 3
Apparently, this is possible on Rust nightly with type ascription, which seems to be a feature designed for this use case (playground):
#![feature(type_ascription)]
use std::convert::*;
struct NewType(pub i32);
impl From<NewType> for i32 {
fn from(src: NewType) -> i32 {
src.0
}
}
fn main() {
let a = NewType(5);
println!("{}", a.into(): i32);
}
Since this is available in an experimental feature, it might be reasonable to conclude that it is otherwise missing from the language proper.
Related videos on Youtube
mrivard
Updated on June 06, 2022Comments
-
mrivard almost 2 years
I'm hoping to be able to use
.into()
to convert a value in a context where type inference is impossible. This is typically when I want to convert a temporary value into some other type for passing it into a generic function. See the following code for an example (playground):use std::convert::*; struct NewType(pub i32); impl From<NewType> for i32 { fn from(src: NewType) -> i32 { src.0 } } fn main() { let a = NewType(5); println!("{}", a.into()); // Understandably won't compile }
I get the error:
error[E0282]: type annotations needed --> src/main.rs:13:20 | 13 | println!("{}", a.into()); | ^^^^^^^^ cannot infer type for `T`
How do I properly tell the compiler that I want to convert
a
intoi32
?I can get it to work right by explicitly feeding
Into
with type arguments:Into::<i32>::into(a)
. This is more verbose and explicit than I was hoping to be able to achieve, especially in a context where I have not importedInto
(std::convert::Into::<i32>::into(a)
).a.into::<i32>()
would be acceptable, but that is not where the type arguments go.a.into() as i32
would look nice, but this exact syntax doesn't work.Is there a trick I am missing?
-
Admin over 7 yearsCould you not avoid the problem by writing
println!("{}", i32::from(a));
, or am I missing some obvious reason why you needinto
? -
mrivard over 7 yearshvd: Uh, that's perfect! I should have said "something like
into
" or "into
orfrom
" or something along those lines. It is sometimes difficult to find the exact level of preciseness for a question ;) Thanks!
-
-
mrivard over 7 yearsI'm not sure why I believed that I had to import
Into
. But you are absolutely right that I don't have to. Thanks :) Type ascription looks like exactly what I was imagining, but I will go for the stablei32:from(a)
instead :) -
Andrey Tyukin over 5 yearsWhy one can expect that there is a
From
: "Library authors should not directly implement [the Into] trait, but should prefer implementing the From trait, which offers greater flexibility and provides an equivalent Into implementation for free, thanks to a blanket implementation in the standard library." - from the documentation ofInto
.