[英]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.