Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/rust/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arguments 是否有可能根据其参数计算Rust函数或trait方法的返回类型?_Arguments_Rust_Type Promotion - Fatal编程技术网

Arguments 是否有可能根据其参数计算Rust函数或trait方法的返回类型?

Arguments 是否有可能根据其参数计算Rust函数或trait方法的返回类型?,arguments,rust,type-promotion,Arguments,Rust,Type Promotion,我能在《铁锈》中取得类似的成就吗?另见 更具体地说:是否可以根据函数或trait方法的参数计算其返回类型,并确保返回类型与其中一个参数的类型相同 考虑以下情况。我有两个结构: #[derive(Debug, Clone, Copy)] struct MySimpleType(f64); #[derive(Debug, Clone, Copy)] struct MyComplexType(f64, f64); 其中,MySimpleType可以通过From特性升级为MyComplexType

我能在《铁锈》中取得类似的成就吗?另见

更具体地说:是否可以根据函数或trait方法的参数计算其返回类型,并确保返回类型与其中一个参数的类型相同

考虑以下情况。我有两个结构:

#[derive(Debug, Clone, Copy)]
struct MySimpleType(f64);

#[derive(Debug, Clone, Copy)]
struct MyComplexType(f64, f64);
其中,
MySimpleType
可以通过
From
特性升级为
MyComplexType

impl From<MySimpleType> for MyComplexType {
    fn from(src: MySimpleType) -> MyComplexType {
        let MySimpleType(x1) = src;
        MyComplexType(x1, 0.0)
    }
 }
但是编译器不知道
O
应该是
S
t
,我必须对大多数方法调用进行注释

我的第二次尝试是使用稍微不同的特性并编写两个实现:

trait Foo<S, T> {
    fn foo(s: S, t: T) -> Self;
}

impl Foo<MySimpleType, MySimpleType> for MySimpleType {
    fn foo(s: MySimpleType, t: MySimpleType) -> Self {
        s + t
    }
}

impl<S, T> Foo<S, T> for MyComplexType
    where MyComplexType: From<S> + From<T>
{
    fn foo(s: S, t: T) -> Self {
        let s: MyComplexType = From::from(s);
        let t: MyComplexType = From::from(t);
        s + t
    }
}
第三次尝试类似于std::ops:{Add,Mul,…}。使用关联的类型,并为每个可能的参数类型组合编写特定的实现

trait Foo<T> {
    type Output;
    fn foo(self, t: T) -> Self::Output;
}

impl<T: Add<Output=T>> Foo<T> for T {
    type Output = Self;
    fn foo(self, t: T) -> Self::Output {
        self + t
    }
}

impl Foo<MySimpleType> for MyComplexType {
    type Output = Self;
    fn foo(self, t: MySimpleType) -> Self::Output {
        let t: Self = From::from(t);
        self + t
    }
}

impl Foo<MyComplexType> for MySimpleType {
    type Output = MyComplexType;
    fn foo(self, t: MyComplexType) -> Self::Output {
        let s: MyComplexType = From::from(self);
        s + t
    }
}

我认为实现提升的最简单方法是创建一个
Promote
特征:

trait Promote<Target> {
    fn promote(self) -> Target;
}

impl<T> Promote<T> for T {
    fn promote(self) -> T { self }
}
编译时不带类型提示,因为
add(1u32,2u64)
只能是
u64
,因此由于
Vec
是同构集合,
add(1u32,1u32)
必须在此处返回
u64


然而,正如您所经历的,有时您需要能够将结果引导到类型推理所能处理的范围之外。没关系,你只需要另一个特质:

trait PromoteTarget {
    type Output;
}

impl<T> PromoteTarget for (T, T) {
    type Output = T;
}
这样,我们就可以重写
baz
签名来正确地解释所有中间类型。不幸的是,我不知道如何在
where
子句中引入别名,所以请做好准备:

fn baz<Result, A, B, C, D>(a: A, b: B, c: C, d: D) -> Result
    where
        A: Promote<<(A, B) as PromoteTarget>::Output>,
        B: Promote<<(A, B) as PromoteTarget>::Output>,
        C: Promote<<(C, D) as PromoteTarget>::Output>,
        D: Promote<<(C, D) as PromoteTarget>::Output>,
        (A, B): PromoteTarget,
        (C, D): PromoteTarget,
        <(A, B) as PromoteTarget>::Output: Promote<Result> + Add<Output = <(A, B) as PromoteTarget>::Output>,
        <(C, D) as PromoteTarget>::Output: Promote<Result> + Add<Output = <(C, D) as PromoteTarget>::Output>,
        Result: Add<Output = Result>
{
    let lhs = foo(a, b).promote();
    let rhs = bar(c, d).promote();
    lhs + rhs
}

“直到需要一个具有n个参数的函数”——你是否考虑编写宏来根据需要生成必要的特征?我已经考虑使用宏,但我很好奇是否存在另一个解决方案。席,马蒂厄?您已经切换到where子句的块样式缩进了吗?
Promote
和@Shepmaster有什么区别:(1)我正在尝试习惯这种块样式缩进的东西,(2)我使用
Promote
来演示这个概念,因为它更容易破解;它开始时有点不一样,老实说,我没意识到它现在正在将
匹配到
。我也不确定这正是OP想要的。。。或者说,类型推断是不够的。还有一个好处是,这个板条箱可以定义标准库类型的升级,尽管我猜
中的
是为扩大整数转换而实现的(总是这样吗?)@Shepmaster:我想,From
最让人恼火的地方是推广到
usize
:它只在
u8
中实现,以防你在8位体系结构上无所事事。因此,事实上,通过自定义特性,您有机会转换为
usize
,以获得更多类型。。。但它确实是一个附带属性:)
trait Promote<Target> {
    fn promote(self) -> Target;
}

impl<T> Promote<T> for T {
    fn promote(self) -> T { self }
}
impl Promote<u64> for u32 {
    fn promote(self) -> u64 { self as u64 }
}

fn add<Result, Left, Right>(left: Left, right: Right) -> Result
    where
        Left: Promote<Result>,
        Right: Promote<Result>,
        Result: Add<Output = Result>
{
    left.promote() + right.promote()
}

fn main() {
    let one: u32 = add(1u32, 1u32);
    let two: u64 = add(1u32, 2u64);
    let three: u64 = add(2u64, 1u32);
    let four: u64 = add(2u64, 2u64);
    println!("{} {} {} {}", one, two, three, four);
}
fn main() {
    let v = vec![add(1u32, 1u32), add(1u32, 2u64)];
    println!("{:?}", v);
}
trait PromoteTarget {
    type Output;
}

impl<T> PromoteTarget for (T, T) {
    type Output = T;
}
impl PromoteTarget for (u32, u64) {
    type Output = u64;
}

impl PromoteTarget for (u64, u32) {
    type Output = u64;
}
fn baz<Result, A, B, C, D>(a: A, b: B, c: C, d: D) -> Result
    where
        A: Promote<<(A, B) as PromoteTarget>::Output>,
        B: Promote<<(A, B) as PromoteTarget>::Output>,
        C: Promote<<(C, D) as PromoteTarget>::Output>,
        D: Promote<<(C, D) as PromoteTarget>::Output>,
        (A, B): PromoteTarget,
        (C, D): PromoteTarget,
        <(A, B) as PromoteTarget>::Output: Promote<Result> + Add<Output = <(A, B) as PromoteTarget>::Output>,
        <(C, D) as PromoteTarget>::Output: Promote<Result> + Add<Output = <(C, D) as PromoteTarget>::Output>,
        Result: Add<Output = Result>
{
    let lhs = foo(a, b).promote();
    let rhs = bar(c, d).promote();
    lhs + rhs
}
============
Foo called
Left: u32
Right: u32
Result: u32
4