I want to convert a value from {integer}
to f32
:
struct Vector3 {
pub x: f32,
pub y: f32,
pub z: f32,
}
for x in -5..5 {
for y in -5..5 {
for z in -5..5 {
let foo: Vector3 = Vector3 { x: x, y: y, z: z };
// do stuff with foo
}
}
}
The compiler chokes on this with a type mismatch error (expecting f32
but getting {integer}
). Unfortunately I can not simply change Vector3
. I'm feeding a C-API with this.
Is there any easy and concise way I can convert x
, y
and z
from {integer}
to f32
?
I guess there is no builtin conversion from i32
or {integer}
to f32
because it could be lossy in certain situations. However, in my case the range I'm using is so small that this wouldn't be an issue. So I would like to tell the compiler to convert the value anyways.
Interestingly, the following works:
for x in -5..5 {
let tmp: i32 = x;
let foo: f32 = tmp as f32;
}
I'm using a lot more that just one foo and one x so this turns hideous really fast.
Also, this works:
for x in -5i32..5i32 {
let foo: f32 = x as f32;
// do stuff with foo here
}
But with my usecase this turns into:
for x in -5i32..5i32 {
for y in -5i32..5i32 {
for z in -5i32..5i32 {
let foo: Vector3 = Vector3 {
x: x as f32,
y: y as f32,
z: z as f32,
};
// do stuff with foo
}
}
}
Which I think is pretty unreadable and an unreasonable amount of cruft for a simple conversion.
What am I missing here?
Since everyone else is answering, I'll chime in with an iterator-flavored solution. This uses
Itertools::cartesian_product
instead of thefor
loops:Unfortunately, closures don't yet implement
Clone
, so I used a small function to perform the mapping. These do implementClone
.If you wanted a helper method:
I'm not sure why you felt the need to specify the
i32
s when usingas
, since this works fine (playground):As Klitos Kyriacou's answer observes, there is no such type as
{integer}
; the compiler gives that error message because it couldn't infer a concrete type forx
. It doesn't actually matter, because there are no implicit conversions from integer types to floating-point types in Rust, or from integer types to other integer types, for that matter. In fact, Rust is quite short on implicit conversions of any sort (the most notable exception beingDeref
coercions).Casting the type with
as
permits the compiler to reconcile the type mismatch, and it will eventually fill in{integer}
withi32
(unconstrained integer literals always default toi32
, not that the concrete type matters in this case).Another option you may prefer, especially if you use
x
,y
andz
for other purposes in the loop, is to shadow them withf32
versions instead of creating new names:(You don't have to write
x: x, y: y, z: z
-- Rust does the right thing when the variable name is the same as the struct member name.)Another option (last one, I promise) is to convert the iterators instead using
map
:However it is a little more dense and may be harder to read than the previous version.
As many problems in Computer Science, it can be solved by applying another layer of indirection.
For example, defining a constructor for
Vec3
:You can use a plethora of other methods (generics, builders, etc...); but a good old constructor is just the simplest.
Another solution this time using a function and traits. playground
From<i16>
is implemented forf32
.So it should be possible to
Of course if your iteration uses values bigger than
i16
(i32
ori64
) this is no longer possible in a safe way and you have to try another way.The only integer types available are
i8
,i16
,i32
, etc. and their unsigned equivalents. There is no such type as{integer}
. This is just a placeholder emitted by the compiler before it has determined the actual type by inference from the whole-method context.The problem is that, at the point where you call
Vector3 {x: x as f32, y: y as f32, z: z as f32}
, it doesn't yet know exactly what x, y and z are, and therefore doesn't know what operations are available. It could use the operations given to determine the type, if it was a bit more intelligent; see bug report for details.There is a conversion from
i32
tof32
, so you should be able to do this: