我想将值转换{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
}
}
}
Run Code Online (Sandbox Code Playgroud)
编译器因类型不匹配错误而窒息(期待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;
}
Run Code Online (Sandbox Code Playgroud)
我使用的只是一个foo和一个x,所以这很快变得可怕.
此外,这有效:
for x in -5i32..5i32 {
let foo: f32 = x as f32;
// do stuff with foo here
}
Run Code Online (Sandbox Code Playgroud)
但随着我的用例,这变成了:
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
}
}
}
Run Code Online (Sandbox Code Playgroud)
我认为这是非常难以理解的,并且对于简单的转换来说是不合理的.
我在这里错过了什么?
我不确定你为什么觉得需要i32在使用时指定s as,因为这很好(游乐场):
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.
}
}
}
Run Code Online (Sandbox Code Playgroud)
正如Klitos Kyriacou的回答所指出的那样,没有这样的类型{integer}; 编译器提供该错误消息,因为它无法推断出具体类型x.它实际上并不重要,因为在Rust 中没有从整数类型到浮点类型的隐式转换,或者从整数类型到其他整数类型的隐式转换.实际上,Rust在任何类型的隐式转换上都很短(最明显的例外是Deref强制转换).
铸造用型as允许编译调和的类型不匹配,并且它最终将填补{integer}与i32(不受约束的整数文字始终默认为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.
}
}
}
Run Code Online (Sandbox Code Playgroud)
(您不必编写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.
}
}
}
Run Code Online (Sandbox Code Playgroud)
然而,它比以前的版本更密集,可能更难阅读.
既然其他人都在回答,我将提出一个迭代器风格的解决方案。这使用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 });
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,闭包尚未实现,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 });
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3619 次 |
| 最近记录: |