[英]Generic function over collections of numbers
我正在嘗試使用assert_approx_eq! 比較結構的元素! 宏。 我正在研究的結構是
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Matrix3D {
n: [[f64; 3]; 3],
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Vector3D {
pub x: f64,
pub y: f64,
pub z: f64,
}
我已經在單獨的迭代器結構的幫助下為這兩種類型實現了IntoIterator
特性
impl IntoIterator for Matrix3D {
type Item = f64;
type IntoIter = Matrix3DIterator;
fn into_iter(self) -> Self::IntoIter {
Matrix3DIterator {
n: self.n,
index: 0,
}
}
}
pub struct Matrix3DIterator {
n: [[f64; 3]; 3],
index: usize,
}
impl Iterator for Matrix3DIterator {
type Item = f64;
fn next(&mut self) -> Option<Self::Item> {
let i = self.index / 3;
let j = self.index % 3;
if i < 3 && j < 3 {
self.index += 1;
Some(self.n[j][i])
} else {
None
}
}
}
impl IntoIterator for Vector3D {
type Item = f64;
type IntoIter = Vector3DIterator;
fn into_iter(self) -> Self::IntoIter {
Vector3DIterator { x: self.x, y: self.y, z: self.z, index: 0}
}
}
pub struct Vector3DIterator {
x: f64,
y: f64,
z: f64,
index: usize,
}
impl Iterator for Vector3DIterator {
type Item = f64;
fn next(&mut self) -> Option<Self::Item> {
let result = match self.index {
0 => Some(self.x),
1 => Some(self.y),
2 => Some(self.z),
_ => None
};
self.index += 1;
result
}
}
在為這些結構編寫測試時,我制作了一個助手 function,它遍歷它們並比較每個元素。 我很難表達這是一種通用的方式,這樣我就可以使用相同的 function 來比較兩個矩陣或兩個向量。 具體來說,集合的類型必須支持減法運算,並為assert_approx_eq!實現一個abs
assert_approx_eq!
宏。 到目前為止我得到的是
use num_traits::Float;
fn elementwise_approx_comparison<I: IntoIterator>(result: I, expected: I) -> ()
where I::Item: Float,
I::Item: std::fmt::Debug {
for (r, e) in std::iter::zip(result, expected) {
assert_approx_eq!(r, e);
}
}
這給出了以下錯誤
error[E0308]: mismatched types
--> src/matrix.rs:411:13
|
411 | assert_approx_eq!(r, e);
| ^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found floating-point number
|
= note: expected associated type `<I as IntoIterator>::Item`
found type `{float}`
= note: this error originates in the macro `assert_approx_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider constraining the associated type `<I as IntoIterator>::Item` to `{float}`
|
407 | fn elementwise_approx_comparison<I: IntoIterator<Item = {float}>>(result: I, expected: I) -> ()
| ++++++++++++++++
編譯器期望關聯類型卻發現浮點數是什么意思? 我如何表達 function elementwise_approx_comparison
應該接受一個集合I
可以做成一個迭代器,並迭代(在這種情況下)浮動類型數字?
問題是assert_approx_eq
試圖比較兩個值和一個文字常量之間的差異,但是 Rust 不知道如何將這個文字常量的類型與值的實際類型統一。 但是assert_approx_eq
允許您指定比較閾值,而Float
定義了一個epsilon()
方法,它為您提供適合這種用途的“小正值”。 因此你可以這樣做:
use num_traits::Float;
fn elementwise_approx_comparison<I: IntoIterator>(result: I, expected: I) -> ()
where I::Item: Float,
I::Item: std::fmt::Debug
{
for (r, e) in std::iter::zip(result, expected) {
assert_approx_eq!(r, e, Float::epsilon());
}
}
或者如果f32::EPSILON
對你來說太小,你可以使用Float::from
自己指定閾值:
use num_traits::Float;
fn elementwise_approx_comparison<I: IntoIterator>(result: I, expected: I) -> ()
where I::Item: Float,
I::Item: std::fmt::Debug
{
for (r, e) in std::iter::zip(result, expected) {
assert_approx_eq!(r, e, Float::from(1e-6f32));
}
}
這是因為宏在定義中使用了浮點數。 您還可以要求該類型與 f64 相當。 然而,這有效地將類型限制為 f64,這並不理想。
fn elementwise_approx_comparison<I: IntoIterator>(result: I, expected: I) -> ()
where
<I as IntoIterator>::Item: Float + PartialOrd<f64>,
I::Item: std::fmt::Debug,
{
for (r, e) in std::iter::zip(result, expected) {
assert_approx_eq!(r, e);
}
}
另一種解決方案是要求調用者為 function 構造 epsilon。
fn elementwise_approx_comparison<I: IntoIterator<Item = F>, F: Float>(
result: I,
expected: I,
eps: F,
) -> ()
where
I::Item: std::fmt::Debug,
{
for (r, e) in std::iter::zip(result, expected) {
assert_approx_eq!(r, e, eps);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.