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?
It is not necessary to specify the i32s when using as, since this works fine (playground):
for x in -5..5 {
for y in -5..5 {
for z in -5..5 {
let foo = Vector3 { // no need to specify the type of foo
x: x as f32,
y: y as f32,
z: z as f32,
};
// etc.
}
}
}
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 for x. 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 being Deref coercions).
Casting the type with as permits the compiler to reconcile the type mismatch, and it will eventually fill in {integer} with i32 (unconstrained integer literals always default to i32, not that the concrete type matters in this case).
Another option you may prefer, especially if you use x, y and z for other purposes in the loop, is to shadow them with f32 versions instead of creating new names:
for x in -5..5 {
let x = x as f32;
for y in -5..5 {
let y = y as f32;
for z in -5..5 {
let z = z as f32;
let foo = Vector3 { x, y, z };
// etc.
}
}
}
(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:
for x in (-5..5).map(|x| x as f32) {
for y in (-5..5).map(|y| y as f32) {
for z in (-5..5).map(|z| z as f32) {
let foo = Vector3 { x, y, z };
// etc.
}
}
}
However it is a little more dense and may be harder to read than the previous version.
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 to f32, so you should be able to do this:
let foo = Vector3 {x: (x as i32) as f32, y: (y as i32) as f32, z: (z as i32) as f32};
Since everyone else is answering, I'll chime in with an iterator-flavored solution. This uses Itertools::cartesian_product instead of the for loops:
extern crate itertools;
use itertools::Itertools;
fn main() {
fn conv(x: i32) -> f32 { x as f32 }
let xx = (-5..5).map(conv);
let yy = xx.clone();
let zz = xx.clone();
let coords = xx.cartesian_product(yy.clone().cartesian_product(zz));
let vectors = coords.map(|(x, (y, z))| Vector3 { x, y, z });
}
Unfortunately, closures don't yet implement Clone, so I used a small function to perform the mapping. These do implement Clone.
If you wanted a helper method:
extern crate itertools;
use itertools::Itertools;
use std::ops::Range;
fn f32_range(r: Range<i32>) -> std::iter::Map<Range<i32>, fn(i32) -> f32> {
fn c(x: i32) -> f32 { x as _ }
r.map(c)
}
fn main() {
let xx = f32_range(-5..5);
let yy = f32_range(-5..5);
let zz = f32_range(-5..5);
let coords = xx.cartesian_product(yy.cartesian_product(zz));
let vectors = coords.map(|(x, (y, z))| Vector3 { x, y, z });
}
From<i16> is implemented for f32.
So it should be possible to
for x in -5..5 {
for y in -5..5 {
for z in -5..5 {
let foo: Vector3 = Vector3 {
x: f32::from(x),
y: f32::from(y),
z: f32::from(z),
};
// do stuff with foo
}
}
}
Of course if your iteration uses values bigger than i16 (i32 or i64) this is no longer possible in a safe way and you have to try another way.
As many problems in Computer Science, it can be solved by applying another layer of indirection.
For example, defining a constructor for Vec3:
impl Vec3 {
fn new(x: i16, y: i16, z: i16) -> Vec3 {
Vec3 { x: x as f32, y: y as f32, z: z as f32 }
}
}
fn main() {
for x in -5..5 {
for y in -5..5 {
for z in -5..5 {
let foo = Vector3::new(x, y, z);
println!("{:?}", foo);
}
}
}
}
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
struct Vector3 {
pub x: f32,
pub y: f32,
pub z: f32,
}
impl Vector3 {
pub fn new<T: Into<f32>>(a: T, b: T, c: T) -> Vector3 {
Vector3 {
x: a.into(),
y: b.into(),
z: c.into(),
}
}
}
fn main() {
for x in -5..5i8 {
for y in -5..5i8 {
for z in -5..5i8 {
let foo: Vector3 = Vector3::new(x, y, z);
// do stuff with foo
}
}
}
}
Related
I have a struct with a couple of operators implemented for it:
use std::ops;
/// Vector of 3 floats
#[derive(Debug, Copy, Clone)]
pub struct Vec3 {
pub x: f32,
pub y: f32,
pub z: f32,
}
/// Add operator
impl ops::Add<&Vec3> for &Vec3 {
type Output = Vec3;
#[inline(always)]
fn add(self, rhs: &Vec3) -> Self::Output {
Vec3 {
x: self.x + rhs.x,
y: self.y + rhs.y,
z: self.z + rhs.z,
}
}
}
/// Subtract operator
impl ops::Sub<&Vec3> for &Vec3 {
type Output = Vec3;
#[inline(always)]
fn sub(self, rhs: &Vec3) -> Self::Output {
Vec3 {
x: self.x - rhs.x,
y: self.y - rhs.y,
z: self.z - rhs.z,
}
}
}
/// Scalar multiplication operator
impl ops::Mul<&Vec3> for f32 {
type Output = Vec3;
#[inline(always)]
fn mul(self, rhs: &Vec3) -> Self::Output {
Vec3 {
x: self * rhs.x,
y: self * rhs.y,
z: self * rhs.z,
}
}
}
I want to use the operators:
let a = Vec3 { x: 0.0, y: 0.5, z: 1.0 };
let b = Vec3 { x: 1.0, y: 0.5, z: 0.0 };
let c = Vec3 { x: 1.0, y: 1.0, z: 0.0 };
let d = Vec3 { x: 0.0, y: 1.0, z: 1.0 };
let result = 2.0 * (a + b) - 3.0 * (c - d);
This code will not compile because the operators are implemented for &Vec3, not for Vec3. To fix the issue, the last line would have to look like this:
let result = &(2.0 * &(&a + &b)) - &(3.0 * &(&c - &d));
Which doesn't look that nice anymore.
I understand that I could implement the operators for Vec3 to avoid that problem, but what if I still want to use immutable references to these vectors on the stack? Is there perhaps a way to give Rust some hint that if I write a + b and there is no operator for Vec3 + Vec3, that it could try and look for a &Vec3 + &Vec3 operator instead, and if found, take the immutable references for both arguments automatically?
No, there is no way of automatically taking a reference when adding two values.
You could write your own macro that does this, I suppose. In usage, it would look like:
thing!{ a + b }
// expands to
(&a + &b)
I'd expect that this macro would quickly become tiresome to write.
See also:
Allow autoderef and autoref in operators — RFC #2147
Tracking issue: Allow autoderef and autoref in operators (experiment) #44762
Does println! borrow or own the variable?
How to implement idiomatic operator overloading for values and references in Rust?
Operator overloading by value results in use of moved value
How can I implement an operator like Add for a reference type so that I can add more than two values at once?
I'd like to create a function that takes an x and y coordinate values and returns a string of the format (x,y):
pub struct Coord {
x: i32,
y: i32,
}
fn main() {
let my_coord = Coord {
x: 10,
y: 12
};
let my_string = coords(my_coord.x, my_coord.y);
fn coords(x: i32, y: i32) -> &str{
let l = vec!["(", x.to_string(), ",", y.to_string(), ")"];
let j = l.join("");
println!("{}", j);
return &j
}
}
This gives me the error:
|
14 | fn coords(x: i32, y: i32) -> &str {
| ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
help: consider using the `'static` lifetime
|
Adding the 'static lifetime seems to cause a host of other problems with this function? How can I fix this?
The more idiomatic approach would be to implement the Display trait for your type Coord which would allow you to call to_string() on it directly, and also would allow you to use it in the println! macro directly. Example:
use std::fmt::{Display, Formatter, Result};
pub struct Coord {
x: i32,
y: i32,
}
impl Display for Coord {
fn fmt(&self, f: &mut Formatter) -> Result {
write!(f, "({}, {})", self.x, self.y)
}
}
fn main() {
let my_coord = Coord { x: 10, y: 12 };
// create string by calling to_string()
let my_string = my_coord.to_string();
println!("{}", my_string); // prints "(10, 12)"
// can now also directly pass to println! macro
println!("{}", my_coord); // prints "(10, 12)"
}
playground
What you are trying to do is not possible. The String you are creating is local to the function and you are trying to return a reference to it.
j will be dropped at the end of the function, so you can't return a reference to it.
You will have to return a String:
fn coords(x: i32, y: i32) -> String {
let l = vec![
"(".into(),
x.to_string(),
",".into(),
y.to_string(),
")".into(),
];
let j = l.join("");
println!("{}", j);
return j;
}
Playground
A better way to do the same:
fn coords(x: i32, y: i32) -> String {
let x = format!("({},{})", x, y);
println!("{}", x);
return x;
}
Playground
this ended up working for me:
pub struct Coord{
x: i32,
y: i32,
}
fn main(){
let my_coord = Coord{
x: 10,
y: 12
};
let my_string = coords(my_coord.x, my_coord.y);
fn coords(x: i32, y: i32) -> String{
let myx = x.to_string();
let myy = y.to_string();
let l = vec!["(", &myx, ",", &myy, ")"];
let j = l.join("");
return j;
}
}
Possible pseudocode for the operation could be:
fn f32_greater(x: f64) -> f32 {
let mut y = x as f32; //I get closest
while f64::from(y) < x {
y = nextafter(y, f32::INFINITY);
}
y
}
fn f32_smaller(x: f64) -> f32 {
let mut y = x as f32; //I get closest
while f64::from(y) > x {
y = nextafter(y, f32::NEG_INFINITY);
}
y
}
I can not find an equivalent to C11's nextafter function in the libc crate or in the methods on f64
For context, I have an R-tree index using f32. I want to search the region with coordinates provided as a f64, so I need the smallest possible region in f32 that includes the f64 value.
This function was removed from the standard library. A solution could be to use the float_extras crate, but I don't really like the way of this crate so here my solution:
mod float {
use libc::{c_double, c_float};
use std::{f32, f64};
#[link_name = "m"]
extern "C" {
pub fn nextafter(x: c_double, y: c_double) -> c_double;
pub fn nextafterf(x: c_float, y: c_float) -> c_float;
// long double nextafterl(long double x, long double y);
// double nexttoward(double x, long double y);
// float nexttowardf(float x, long double y);
// long double nexttowardl(long double x, long double y);
}
pub trait NextAfter {
fn next_after(self, y: Self) -> Self;
}
impl NextAfter for f32 {
fn next_after(self, y: Self) -> Self {
unsafe { nextafterf(self, y) }
}
}
impl NextAfter for f64 {
fn next_after(self, y: Self) -> Self {
unsafe { nextafter(self, y) }
}
}
pub trait Succ {
fn succ(self) -> Self;
}
impl Succ for f32 {
fn succ(self) -> Self {
self.next_after(f32::INFINITY)
}
}
impl Succ for f64 {
fn succ(self) -> Self {
self.next_after(f64::INFINITY)
}
}
pub trait Pred {
fn pred(self) -> Self;
}
impl Pred for f32 {
fn pred(self) -> Self {
self.next_after(f32::NEG_INFINITY)
}
}
impl Pred for f64 {
fn pred(self) -> Self {
self.next_after(f64::NEG_INFINITY)
}
}
}
use crate::float::{Pred, Succ};
use num_traits::cast::{FromPrimitive, ToPrimitive};
fn f32_greater<T>(x: T) -> Option<f32>
where
T: ToPrimitive + FromPrimitive + std::cmp::PartialOrd,
{
let mut y = x.to_f32()?;
while T::from_f32(y)? < x {
y = y.succ();
}
Some(y)
}
fn f32_smaller<T>(x: T) -> Option<f32>
where
T: ToPrimitive + FromPrimitive + std::cmp::PartialOrd,
{
let mut y = x.to_f32()?;
while T::from_f32(y)? > x {
y = y.pred();
}
Some(y)
}
fn main() {
let a = 42.4242424242424242;
println!(
"{:.16?} < {:.16} < {:.16?}",
f32_smaller(a),
a,
f32_greater(a)
);
}
I don't understand why they don't include it in the num crate.
The following function calculates the number of orbits it takes for an mandelbrot fractal initial value to "escape":
extern crate num;
fn mandel_escape(x: f32, y: f32, limit: f32, orbits: u32) -> Option<u32> {
let c = num::complex::Complex32::new(x, y);
let mut z = c;
for i in 0 .. orbits {
z = z * z + c;
if z.norm_sqr() > limit { return Some(i); }
}
None
}
I understand that there is no guaranteed tail call optimization in Rust. How might I be able to remove the mutable variable in this function without recursion?
It's not possible.
You need to create the values of z for each iteration at some point. So either you have a mutable location to store each one in, or you need space for all of them.
You can hide the mutability inside an iterator, though:
struct MandelIterator {
c: f32,
z: f32,
}
fn mandel_iter(c: f32) -> MandelIterator {
MandelIterator { c: c, z: 0.0 }
}
impl Iterator for MandelIterator {
type Item = f32;
fn next(&mut self) -> Option<Self::Item> {
self.z = self.z * self.z + self.c;
Some(self.z)
}
}
fn mandel_escape(x: f32, y: f32, limit: f32, orbits: usize) -> Option<usize> {
for (i, z) in mandel_iter(x*y).enumerate().take(orbits) {
if z.abs() > limit { return Some(i); }
}
None
}
fn main() {
println!("{:?}", mandel_escape(1.00001, 1.00001, 40999.0, 4));
}
Given this code (also here):
struct Vector2 {
x: int,
y: int
}
impl Vector2 {
pub fn new(xs: int, ys: int) -> Vector2 {
Vector2 {
x: xs,
y: ys
}
}
fn add(&self, otr: Vector2) -> &Vector2 {
self.x += otr.x; // cannot assign to immutable field (line 15)
self.y += otr.y; // cannot assign to immutable field (line 16)
return self; // lifetime mismatch (line 17)
}
}
fn main() {
let mut vec1 = Vector2::new(42, 12);
println(fmt!("vec1 = [x: %?, y: %?]", vec1.x, vec1.y));
let vec2 = Vector2::new(13, 34);
println(fmt!("vec2 = [x: %?, y: %?]", vec2.x, vec2.y));
let vec3 = vec1.add(vec2);
println(fmt!("vec1 + vec2 = [x: %?, y: %?]", vec3.x, vec3.y))
}
I'm having issues with lines 15-17.
For lines 15 and 16, can someone explain what the best way to change those two variables would be? It seems I'm either not using self right or I'm missing a mut somewhere.
For line 17, it's giving me a lifetime mismatch, also saying:
mismatched types: expected '&Vector2' but found '&Vector2'...the anonymous lifetime #1 defined on the block at 14:41 does not necessarily outlive the anonymous lifetime #2 defined on the block at 14:41.
Does anyone know of any way to fix these two issues?
If you wish to have add being a mutating operation, it should take &mut self rather than &self.
If you wish to have add create a new Vector2, then don't try mutating self—clone it (assuming 0.8-pre; on 0.7, you'd copy it instead with copy self) and modify the clone, or create a new instance with the same type. (This will be faster in a case like add.
While you're at it, don't just have a method called add: implement std::ops::Add, and + will work! (There is no += yet—see https://github.com/mozilla/rust/issues/5992.)
The final code:
struct Vector2 {
x: int,
y: int,
}
impl Vector2 {
pub fn new(x: int, y: int) -> Vector2 {
Vector2 {
x: x,
y: y,
}
}
}
impl Add<Vector2, Vector2> for Vector2 {
fn add(&self, rhs: &Vector2) -> Vector2 {
Vector2 {
x: self.x + rhs.x,
y: self.y + rhs.y,
}
}
}
fn main() {
let vec1 = Vector2::new(42, 12);
println(fmt!("vec1 = %?", vec1));
// 0.8-pre hint: use printfln!(...) instead of println(fmt!(...))
let vec2 = Vector2::new(13, 34);
println(fmt!("vec2 = %?", vec2));
let vec3 = vec1 + vec2;
println(fmt!("vec1 + vec2 = %?", vec3));
}
And its output:
vec1 = {x: 42, y: 12}
vec2 = {x: 13, y: 34}
vec1 + vec2 = {x: 55, y: 46}