[英]Converting {integer} to f32 in Rust
我想将值从{integer}
转换为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
}
}
}
编译器因类型不匹配错误而阻塞了此错误(期望f32
但得到{integer}
)。 不幸的是,我不能简单地更改Vector3
。 我为此提供了C-API。
有什么简单明了的方法可以将x
, y
和z
从{integer}
为f32
?
我猜没有从i32
或{integer}
到f32
内置转换,因为它在某些情况下可能有损。 但是,就我而言,我所使用的范围很小,因此这不会成为问题。 所以我想告诉编译器无论如何都要转换值。
有趣的是,以下作品:
for x in -5..5 {
let tmp: i32 = x;
let foo: f32 = tmp as f32;
}
我使用的不仅仅是一个foo和一个x,所以这变得非常可怕。
同样,这可行:
for x in -5i32..5i32 {
let foo: f32 = x as f32;
// do stuff with foo here
}
但是用我的用例,它变成了:
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
}
}
}
对于简单的转换,我认为这是非常难以理解的,并且不合理。
我在这里想念什么?
我不确定您为什么在使用as
时会觉得需要指定i32
,因为这样可以很好地工作( 游乐场 ):
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.
}
}
}
正如克里托斯·基里亚库(Klitos Kyriacou)的回答所观察到的,没有{integer}
这样的类型; 编译器给出该错误消息,因为它无法推断x
的具体类型。 实际上并不重要,因为在此情况下,Rust中没有从整数类型到浮点类型的隐式转换,也没有从整数类型到其他整数类型的隐式转换。 实际上,Rust在任何形式的隐式转换上都非常短(最著名的例外是Deref
强制)。
使用as
i32
转换类型使编译器可以协调类型不匹配的情况,最终它将用i32
填充{integer}
( 无约束的整数常量始终默认为i32
,在这种情况下,具体类型并不重要)。
您可能更喜欢另一种选择,尤其是在循环中将x
, y
和z
用于其他目的时,请使用f32
版本对其进行阴影而不是创建新名称:
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.
}
}
}
(您不必写x: x, y: y, z: z
-当变量名与结构成员名相同时,Rust做对了。)
另一个选择(我保证,最后一个选择)是转换迭代器,而不是使用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.
}
}
}
但是,它比以前的版本更密集,可能更难阅读。
可用的唯一整数类型是i8
, i16
, i32
等,以及它们的无符号等效项。 没有{integer}
这样的类型。 这只是编译器在通过从整个方法上下文进行推断来确定实际类型之前发出的占位符。
问题是,在调用Vector3 {x: x as f32, y: y as f32, z: z as f32}
那Vector3 {x: x as f32, y: y as f32, z: z as f32}
,它尚不确切知道x,y和z是什么,因此不知道不知道可以进行哪些操作。 如果它更智能,它可以使用给定的操作来确定类型。 有关详细信息,请参见错误报告 。
从i32
到f32
都有转换,因此您应该可以执行以下操作:
let foo = Vector3 {x: (x as i32) as f32, y: (y as i32) as f32, z: (z as i32) as f32};
由于其他所有人都在回答,因此我将介绍迭代器风格的解决方案。 这使用Itertools::cartesian_product
代替for
循环:
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 });
}
不幸的是,闭包尚未实现Clone
,因此我使用了一个小函数来执行映射。 这些确实实现了Clone
。
如果需要帮助方法:
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>
为f32
实现 。
所以应该有可能
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
}
}
}
当然,如果您的迭代使用的值大于i16
( i32
或i64
),则这将不再是安全的方式,您必须尝试另一种方式。
与计算机科学中的许多问题一样,可以通过应用另一层间接解决。
例如,为Vec3
定义一个构造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);
}
}
}
}
您可以使用多种其他方法(泛型,构建器等); 但是一个好的旧构造函数只是最简单的。
这次使用功能和特征的另一个解决方案。 操场
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
}
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.