提问人:exocortex 提问时间:9/27/2022 最后编辑:exocortex 更新时间:9/27/2022 访问量:302
在 Rust 中需要使用 f64 的泛型类型的标量乘法
Require scalar multiplication of a generic type with f64 in Rust
问:
我觉得我有两半的问题,不知道如何将它们组合在一起。 一方面,有“derive_more”板条箱,它允许自动派生特定类型的“添加”和“Mul”(+更多)特征。我已经成功地使用它为特定类型实现了以下函数,我自动为其派生了这些特征。
另一方面,我想编写一个通用函数,稍后将使用这些“Add”和“Mul”(+更多)特征。然而,它不起作用。(对于任何感兴趣的人,我想实现一个通用的 Runge-Kutta 函数来求解微分方程)。
pub fn update_rk4<T>(f: fn(&T) -> T, state: &mut T, dt: f64)
where
T: Sized
+ std::ops::Mul<Output = T>
+ std::ops::Add<Output = T>
+ std::ops::AddAssign,
{
// runge kutta 4 method creates 4 "helper steps"
let k1 = f(state);
let k2 = f(&(*state + k1 * 0.5 * dt));
let k3 = f(&(*state + k2 * 0.5 * dt));
let k4 = f(&(*state + k3 * dt));
*state += (k1 + k2 * 2.0 + k3 * 2.0 + k4) * (1.0 / 6.0 * dt);
}
我被困在这里。我收到很多这样的错误消息:
error[E0308]: mismatched types
--> src/integrator.rs:7:32
|
1 | pub fn update_rk4_with_f<T>(f: fn(&T) -> T, state: &mut T, dt: f64)
| - this type parameter
...
7 | let k2 = f(&(*state + k1 * 0.5 * dt));
| ^^^ expected type parameter `T`, found floating-point number
|
= note: expected type parameter `T`
found type `{float}`
我在这里做错了什么?另外:我试图解决的问题的名称是什么?我想我也缺少一个好的搜索词来放入谷歌。
编辑:
在下面 Matthieu M. 的精彩回答的帮助下,我解决了我的问题。我尝试将“Mul<Output = T>”替换为“Mul<Rhs = f64,Output = T>”,但仍然出现错误。事实证明,这个想法是正确的,因为在特征实现中,“Rhs”默认为“T”,因此必须手动设置 - 但没有“Rhs”。解决方案很简单:“Mul<f64,输出 = T>”。然后,有了“复制”特征,一切都奏效了。最终的工作代码如下所示:
pub fn update_rk4<T>(f: fn(&T) -> T, state: &mut T, dt: f64)
where
T: Sized + Copy
+ std::ops::Mul<f64, Output = T>
+ std::ops::Add<T, Output = T>
+ std::ops::AddAssign,
{
// runge kutta 4 method creates 4 "helper steps"
let k1 = f(state);
let k2 = f(&(*state + k1 * 0.5 * dt));
let k3 = f(&(*state + k2 * 0.5 * dt));
let k4 = f(&(*state + k3 * dt));
*state += (k1 + k2 * 2.0 + k3 * 2.0 + k4) * (1.0 / 6.0 * dt);
}
答:
另外:我试图解决的问题的名称是什么?
我不知道任何具体的名字。
我在这里做错了什么?
更仔细地查看特征定义:Add
pub trait Add<Rhs = Self> {
type Output;
fn add(self, rhs: Rhs) -> Self::Output;
}
有一个默认参数(键入时)表示右侧参数的类型:除非指定,否则此参数将为 。Add
Self
这正是错误消息告诉您的:
^^^ expected type parameter `T`, found floating-point number
您指定了 ,因此右手参数应该是 a 和 是文字,而不是 .T: Add<Output = Self>
T
0.5
T
您可以通过以下几种方式之一解决此问题:
- 混合算术:实现 or for ,并指定为边界。
Add<f32>
Add<f64>
T
T: Add<fXX, Output = Self>
- 无误转换:在尝试操作之前添加补充绑定(或)并将文本转换为。
T: From<f32>
T: From<f64>
T
- 自定义特征:使用您需要的常量创建一个新特征,并为您想要的所有特征实现该特征。
T
虽然很吸引人,但如果混合算术是原语,它可能不是你想要的解决方案,因为你不能自己添加实现。T
如果任何(或)可以转换为 .使用将允许容易出错的转换,但也需要返回错误,这会恶化人体工程学。f32
f64
T
TryFrom
后一种自定义特征方法更为严厉,但允许规避先前方法的局限性。
使用哪种方式取决于应该是什么。如果可能的话,我个人更喜欢 Infallible Conversion,因为它是一个轻量级的要求——不需要实现 5 或 10 个特征——或者如果转换不能是绝对可靠的,则使用自定义特征。T
评论
Add
Mul
评论