作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
Rust 初学者。
当尝试实现(仅用于学习)具有四种基本算术的维度标量系统时,即实现如下目标:
fn main() {
let length1 = 3.meters();
// ^^^^^^ to be implemented
let length2 = 4.meters();
let area = length1 * length2;
println!("{:?}", area); // maybe something like DimensionedScalar{value: 12, unit: {meter: 2}}, where {meter: 2} means meter-square
let temperature = 243.kelvins();
// ^^^^^^^ to be implemented
let dilation_rate = 3.2.meters() * 1.meters() * 1.meters() / 1.kelvins();
let non_sensical = temperature + dilation_rate; // should raise error because of dimensionality mismatch
}
,我遇到了维度检查的问题:
在这种情况下,我们似乎需要一个依赖类型,因为单位的指数可以是任意数字。
然后它需要:
+
和 -
)返回 Result
类型而不是标量类型,这对于当前的 来说似乎是不可能的>std::ops::{ Add, Sub }
特征定义,或最终,我当然可以放弃 +
和 -
的原生语法并定义我自己的方法,例如 subtract()
或 add_with()
这样我就可以返回一个 Result
类型。但这无疑会不那么酷。
有什么建议吗?
最佳答案
一般技术是将 n 维类型代数视为 ℤn 中的向量空间,其中每个向量系数对应于单位的指数。例如,这个向量空间的“基础”可以是 SI 单位。那么单位的乘法在这个向量空间就变成了加法,除法就变成了减法。您可以将向量空间的系数存储为模板参数,这样可以确保在具有相同单位的值之间实现加法/减法。为了帮助解决这个问题,我建议使用 typenum
箱。最后,您可以添加类型别名以使其更易于使用。
仅以 Meter
、Kelvin
和 Second
为例,使用 f64
作为存储:
use core::marker::PhantomData;
use typenum::{Integer, Z0, P1};
#[derive(Clone, Copy)]
struct SIValue<M, K, S> {
val: f64,
unit: PhantomData<(M, K, S)>,
}
type Scalar = SIValue<Z0, Z0, Z0>; // Unitless - zero vector.
type Meter = SIValue<P1, Z0, Z0>; // Basis type vector for meter.
type Kelvin = SIValue<Z0, P1, Z0>; // Basis type vector for Kelvin.
type Second = SIValue<Z0, Z0, P1>; // Basis type vector for second.
fn main() {
let g = Meter::new(9.8) / Second::new(1.0) / Second::new(1.0);
println!("Gravitional constant: {}", g);
let mut dist = Meter::new(0.0);
let mut accel = Meter::new(0.0) / Second::new(1.0);
let mut t = Second::new(0.0);
let dt = Second::new(0.001);
let maxt = Second::new(5.0);
while t < maxt {
accel = accel + dt * g;
dist = dist + accel * dt;
t = t + dt;
}
println!("Distance after falling for {t:.1}: {dist:.1}");
println!("Acceleration after {t:.1}: {accel:.1}");
}
打印:
Gravitional constant: 9.8 m s^-2
Distance after falling for 5.0 s: 122.5 m
Acceleration after 5.0 s: 49.0 m s^-1
给定以下实现(或在 playground 中):
use core::ops::{Add, Sub, Mul, Div};
use core::fmt;
impl<M, K, S> SIValue<M, K, S> {
fn new(val: f64) -> Self {
Self { val, unit: PhantomData }
}
}
impl<M: Integer, K: Integer, S: Integer> fmt::Display for SIValue<M, K, S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let write_unit = |f: &mut fmt::Formatter, unit, exp| {
match exp {
0 => Ok(()),
1 => write!(f, " {}", unit),
n => write!(f, " {}^{}", unit, exp),
}
};
write!(f, "{}", self.val)?;
write_unit(f, "m", M::to_i32())?;
write_unit(f, "K", K::to_i32())?;
write_unit(f, "s", S::to_i32())
}
}
impl<M, K, S> Add for SIValue<M, K, S> {
type Output = Self;
fn add(self, rhs: SIValue<M, K, S>) -> Self::Output {
SIValue::new(self.val + rhs.val)
}
}
impl<M, K, S> Sub for SIValue<M, K, S> {
type Output = Self;
fn sub(self, rhs: SIValue<M, K, S>) -> Self::Output {
SIValue::new(self.val - rhs.val)
}
}
impl<LM, LK, LS, RM, RK, RS> Mul<SIValue<RM, RK, RS>> for SIValue<LM, LK, LS>
where
LM: Add<RM>, LK: Add<RK>, LS: Add<RS>,
{
type Output = SIValue<
<LM as Add<RM>>::Output,
<LK as Add<RK>>::Output,
<LS as Add<RS>>::Output,
>;
fn mul(self, rhs: SIValue<RM, RK, RS>) -> Self::Output {
SIValue::new(self.val * rhs.val)
}
}
impl<LM, LK, LS, RM, RK, RS> Div<SIValue<RM, RK, RS>> for SIValue<LM, LK, LS>
where
LM: Sub<RM>, LK: Sub<RK>, LS: Sub<RS>,
{
type Output = SIValue<
<LM as Sub<RM>>::Output,
<LK as Sub<RK>>::Output,
<LS as Sub<RS>>::Output,
>;
fn div(self, rhs: SIValue<RM, RK, RS>) -> Self::Output {
SIValue::new(self.val / rhs.val)
}
}
如果你试图添加错误的单位,你会得到一个错误,就像你在上面的例子中做 accel + dt
一样:
error[E0308]: mismatched types
--> src/main.rs:17:25
|
17 | accel = accel + dt;
| ^^ expected struct `PInt`, found struct `Z0`
|
= note: expected struct `SIValue<PInt<UInt<UTerm, B1>>, _, NInt<UInt<UTerm, B1>>>`
found struct `SIValue<Z0, _, PInt<UInt<UTerm, B1>>>`
不幸的是,错误消息不是特别好。
关于rust - 如何在 Rust 中实现带量纲的标量算法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73091949/
我是一名优秀的程序员,十分优秀!