当使用'num::Float'特性并与Rust中的基元类型交互时,如何最小化样板文件的数量

当使用'num::Float'特性并与Rust中的基元类型交互时,如何最小化样板文件的数量,rust,Rust,当使用num::Floattrait并与Rust中的原始类型交互时,有没有一种好的方法来最小化样板文件的数量?作为一个例子,考虑一个写得很差的二次方程求解器< /P> // External libraries use num::Float; // Poorly written quadratic formula solver for a x^2 + bx + c fn myquad <Real> (a : Real, b : Real, c : Real) -> Optio

当使用
num::Float
trait并与Rust中的原始类型交互时,有没有一种好的方法来最小化样板文件的数量?作为一个例子,考虑一个写得很差的二次方程求解器< /P>
// External libraries
use num::Float;

// Poorly written quadratic formula solver for a x^2 + bx + c
fn myquad <Real> (a : Real, b : Real, c : Real) -> Option<(Real,Real)>
where
    Real : Float
{
    let mysqrt = Real::sqrt(b.powi(2)-Real::from(4.0)?*a*c);
    let r1 = (-b+mysqrt)/(Real::from(2.0)?*a);
    let r2 = (-b-mysqrt)/(Real::from(2.0)?*a);
    Some((r1,r2))
}

// Write a couple of tests
fn main() {
    let r1 = myquad::<f32> (1.0,1.0,-6.0).unwrap();
    println!("Roots of (x-2) (x+3):  ({},{})",r1.0,r1.1);
    let r2 = myquad::<f64> (6.0,5.0,-4.0).unwrap();
    println!("Roots of (2x-1) (3x+4):  ({},{})",r2.0,r2.1);
}
//外部库
使用num::Float;
//x^2+bx+c的二次公式求解器写得很差
fn myquad(a:Real,b:Real,c:Real)->选项
哪里
真的:浮动
{
设mysqrt=Real::sqrt(b.powi(2)-Real::from(4.0)?*a*c);
设r1=(-b+mysqrt)/(Real::from(2.0)?*a);
设r2=(-b-mysqrt)/(Real::from(2.0)?*a);
一些((r1,r2))
}
//写几个测试
fn main(){
设r1=myquad::(1.0,1.0,-6.0).unwrap();
println!((x-2)(x+3)的根:({},{})”,r1.0,r1.1;
设r2=myquad::(6.0,5.0,-4.0).unwrap();
println!((2x-1)(3x+4)的根:({},{})”,r2.0,r2.1;
}

我希望
myquad
例程能够适用于除
f32
f64
之外的各种浮点类型,但也适用于它们。也就是说,有一组重复的包装器,其形式为
Real::from(x)?
,其中x是一种基本浮点类型。虽然我理解类型一致性的需要,但这有点冗长,我担心这些包装器对于包含大量原语的更复杂例程的可管理性。有没有更好的方法来处理这些转换,或者让它们隐式工作?当然,答案可能是否定的,但我想在处理更复杂的例程之前了解这一成本。

您遇到这一障碍的原因是,您希望
num::Float
成为一种实现的特性它不是。其目的是作为一个整体

它是为
f32
f64
实现的,允许您使用它在这些类型上实现的所有方法,而无需在类型本身中实现它们

然而,这并不意味着您可以神奇地添加一个
t:Float
绑定并脱离困境,因为您的操作需要乘法和减法。因此,您的常量(您自己发现的)需要实现
Sub
Mul
,其中
X
是您为常量选择的类型

然而,有一个技巧。如果您知道常量的类型。。。您可以从中要求
(其中X是常量的类型)。这意味着您可以以要求浮动大小的下限为代价,轻松修复这一混乱

此下限要求在您的情况下不是问题,因为您依赖于
num::Float
上声明的
powi
方法,并且此特性仅针对两种基本类型实现:
f32
f64
。如果你想使用,比如说,
half::f16
,你需要去掉对
powi
的调用。因此,要求将
f32
作为下限是完全可以接受的

fn myquad<T:Float + From<f32>>(a : T, b: T, c: T) -> Option<(T, T)>
{
    let mysqrt = (b.powi(2) - a * c * (4.0.into())).sqrt();
    let r1 = (-b+mysqrt)/(a * 2.0.into());
    let r2 = (-b-mysqrt)/(a * 2.0.into());
    Some((r1,r2))
}
fn myquad(a:T,b:T,c:T)->选项
{
设mysqrt=(b.powi(2)-a*c*(4.0.into()).sqrt();
设r1=(-b+mysqrt)/(a*2.0.into());
设r2=(-b-mysqrt)/(a*2.0.into());
一些((r1,r2))
}

我认为,从样板文件的角度来看,这差不多是你能做到的最低限度。

你遇到这个障碍的原因是因为你期望
num::Float
成为一个可实现的特性它不是。其目的是作为一个整体

它是为
f32
f64
实现的,允许您使用它在这些类型上实现的所有方法,而无需在类型本身中实现它们

然而,这并不意味着您可以神奇地添加一个
t:Float
绑定并脱离困境,因为您的操作需要乘法和减法。因此,您的常量(您自己发现的)需要实现
Sub
Mul
,其中
X
是您为常量选择的类型

然而,有一个技巧。如果您知道常量的类型。。。您可以从
中要求
(其中X是常量的类型)。这意味着您可以以要求浮动大小的下限为代价,轻松修复这一混乱

此下限要求在您的情况下不是问题,因为您依赖于
num::Float
上声明的
powi
方法,并且此特性仅针对两种基本类型实现:
f32
f64
。如果你想使用,比如说,
half::f16
,你需要去掉对
powi
的调用。因此,要求将
f32
作为下限是完全可以接受的

fn myquad<T:Float + From<f32>>(a : T, b: T, c: T) -> Option<(T, T)>
{
    let mysqrt = (b.powi(2) - a * c * (4.0.into())).sqrt();
    let r1 = (-b+mysqrt)/(a * 2.0.into());
    let r2 = (-b-mysqrt)/(a * 2.0.into());
    Some((r1,r2))
}
fn myquad(a:T,b:T,c:T)->选项
{
设mysqrt=(b.powi(2)-a*c*(4.0.into()).sqrt();
设r1=(-b+mysqrt)/(a*2.0.into());
设r2=(-b-mysqrt)/(a*2.0.into());
一些((r1,r2))
}

我认为,就样板而言,这差不多是你能做到的最低限度了。

小修正;如果您颠倒操作顺序,您甚至不需要显式强制转换!看起来不错。谢谢对于其他人来说,Sebastien指的是类似
4.0*a*c
的操作顺序。当作为
a*c*4.0.into()写入时,类型推断允许Rust为
4.0
的转换确定正确的类型。对于
4.0.into()*a*c
,情况并非如此,这会导致编译器错误“无法推断T的类型”小更正;如果您颠倒操作顺序,您甚至不需要显式强制转换!看起来不错。谢谢对于其他人来说,Sebastien指的是类似
4.0*a*c
的操作顺序。当作为
a*c*4.0.into()写入时,类型推断允许Rust确定
4.0
转换的正确类型