如何在特征界限中指定`std :: ops :: Mul`的预期结果?

时间:2018-04-23 05:23:37

标签: generics rust operator-overloading traits

我有:

use std::ops::{Add, Div, Mul, Neg, Sub};

pub trait Hilbert: Add + Sub + Mul + Div + Neg + Mul<f64> + Div<f64> + Sized {
    fn dot(&self, other: &Self) -> f64;
    fn magnitude(&self) -> f64;
}

fn g<T: Hilbert>(x: T) -> f64 {
    return (x * 2.0).dot(x);
}

......产生:

error[E0599]: no method named `dot` found for type `<T as std::ops::Mul<f64>>::Output` in the current scope
 --> src/main.rs:9:22
  |
9 |     return (x * 2.0).dot(x);
  |                      ^^^
  |
  = help: items from traits can only be used if the trait is implemented and in scope
  = note: the following trait defines an item `dot`, perhaps you need to implement it:
          candidate #1: `Hilbert`

我认为这意味着Rust无法保证具有特征T的{​​{1}}类型的Hilbert具有std::ops::Mul类型的实现等于::Output(a T)。

但我知道(和/或希望要求)所有Hilbert的情况都是如此,因此像Hilbert这样的函数可以编写。

我会考虑为g()

提出std::ops::Mul::Output
Hilbert

...但这同时存在以下问题:(a)我无法部分实施&#34;特征,并将被迫为所有impl<T: Hilbert> Mul<f64> for T { type Output = T; } 生成函数Mul::mul()的通用实现,但Hilberts的实际实现将取决于Mul::mul()的具体实现; (b)似乎我根本不允许写这个特性:

Hilbert

如何说服Rust error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g. `MyStruct<T>`); only traits defined in the current crate can be implemented for a type parameter --> src/main.rs:12:1 | 12 | / impl<T: Hilbert> Mul<f64> for T { 13 | | type Output = T; 14 | | } | |_^ * Hilbert - &gt; f64必须举行?

1 个答案:

答案 0 :(得分:2)

  

如何说服Rust Hilbert * f64 - &gt; Hilbert必须举行?

添加特征绑定<T as Mul<f64>>::Output: Hilbert。但是,这样做会在您的设计中发现更多问题:

  1. Hilbert.dot()将第二个参数作为参考,而不是值。但是将相关行更改为(x * 2.0).dot(&x)会导致另一个错误:“预期的关联类型,找到的类型参数”
  2. 这是因为您定义了dotSelf,但可能会有不同的Hilbert实现。 dot必须是通用的:fn dot<H: Hilbert>(&self, other: &H) -> f64;
  3. 最后,借用检查器点击:(x * 2.0).dot(&x)将不允许您使用x两次,因为mul按值获取其参数。您将需要添加一个绑定Mul<&'a Self>才能传入引用(使用生命周期参数感染您的API)或使x克隆(我不认为可复制)。< / LI>

    将所有上述结果应用于此工作(?)可编译代码:

    pub trait Hilbert: Add + Sub + Mul + Div + Neg + Mul<f64> + Div<f64> + Sized {
        fn dot<H: Hilbert>(&self, other: &H) -> f64;
        fn magnitude(&self) -> f64;
    }
    
    fn g<T: Hilbert + Clone>(x: T) -> f64
    where
        <T as Mul<f64>>::Output: Hilbert,
    {
        (x.clone() * 2.0).dot(&x)
    }
    

    如果Hilbert.dot不应该是通用的,因为Hilbert的不同实现不需要交互,代码可以稍微简单一些(就特征界限而言):

    pub trait Hilbert:
        Add + Sub + Mul + Div + Neg + Mul<f64, Output = Self> + Div<f64, Output = Self> + Sized
    {
        fn dot(&self, other: &Self) -> f64;
        fn magnitude(&self) -> f64;
    }
    
    fn g<T: Hilbert + Clone>(x: T) -> f64 {
        (x.clone() * 2.0).dot(&x)
    }
    

    然而,根据我对希尔伯特变换的了解,后一种情况似乎不太有用。