没有找到名为len的方法,类型为<t as =“”trait =“”> ::在当前范围中键入

时间:2018-05-17 13:06:52

标签: generics rust

我想通知VecLengthDirector AbstractVecLengthBuider的关联类型始终为[i32; n](n∈N)。我写了以下代码:

struct VecLengthDirector<T> {
    builder: T,
}

impl<T> VecLengthDirector<T>
where
    T: AbstractVecLengthBuider,
{
    fn construct(&self) -> f64 {
        let s = self.builder.get_start_point();
        let e = self.builder.get_end_point();

        let mut sum: i32 = 0;
        for i in 0..s.len() {
            sum += (s[i] - e[i]).pow(2);
        }

        (sum as f64).sqrt()
    }
}

trait AbstractVecLengthBuider {
    type PointType;
    fn add_start_point(&mut self, point: Self::PointType);
    fn get_start_point(&self) -> Self::PointType;
    fn add_end_point(&mut self, point: Self::PointType);
    fn get_end_point(&self) -> Self::PointType;
}

报告的错误。

error[E0599]: no method named `len` found for type `<T as AbstractVecLengthBuider>::PointType` in the current scope
  --> src/main.rs:14:23
   |
14 |         for i in 0..s.len() {
   |                       ^^^

error[E0608]: cannot index into a value of type `<T as AbstractVecLengthBuider>::PointType`
  --> src/main.rs:15:21
   |
15 |             sum += (s[i] - e[i]).pow(2);
   |                     ^^^^

error[E0608]: cannot index into a value of type `<T as AbstractVecLengthBuider>::PointType`
  --> src/main.rs:15:28
   |
15 |             sum += (s[i] - e[i]).pow(2);
   |                            ^^^^

2 个答案:

答案 0 :(得分:1)

  

我想通知VecLengthDirector AbstractVecLengthBuider的关联类型总是[i32; n](n∈N)。

你不能。如果要对关联类型使用特定操作,则需要使用一个或多个特征约束。

例如,索引需要实现Index特征。

没有包含<[_]>::len的特征。也就是说,您可以通过滥用迭代器来编写一个应该涵盖大多数相关案例的文章:

pub trait Length {
    fn len(self) -> usize;
}

impl<'a, T> Length for &'a T
where
    &'a T: IntoIterator,
    <&'a T as IntoIterator>::IntoIter: ::std::iter::ExactSizeIterator,
{
    fn len(self) -> usize {
        self.into_iter().len()
    }
}

pub trait RefLength {
    fn len(&self) -> usize;
}

impl<T> RefLength for T
where
    for<'a> &'a T: Length,
{
    fn len(&self) -> usize {
        Length::len(self)
    }
}

然后,你可以在特质定义中使用类似type PointType: Index<usize> + RefLength;的东西。

答案 1 :(得分:1)

<强>的QuickFix

您需要指定PointType的种类。例如T: AbstractVecLengthBuider<PointType = [i32]>>。但是,[i32]的大小在编译时是未知的,因此您可以将其替换为Vec<i32>T: AbstractVecLengthBuider<PointType = Vec<i32>>

如果您仍想要通用,则可以将PointType限制为[i32]可借用:

impl<T, P> VecLengthDirector<T>
where
    T: AbstractVecLengthBuider<PointType = P>,
    P: ::std::borrow::Borrow<[i32]>,
{
    fn construct(&self) -> f64 {
        let s = self.builder.get_start_point().borrow();
        let e = self.builder.get_end_point().borrow();
        // ...
    }
}

这不是惯用的Rust。

惯用生锈方式

您的循环可以重写为更惯用的Rust:

s.iter()
    .zip(e.iter())
    .map(|(se, ee)| (se - ee).pow(2) as f64)
    .sum()

然后你只需要约束PointType可以在i32上进行迭代:

impl<T, P> VecLengthDirector<T>
where
    T: AbstractVecLengthBuider<PointType = P>,
    P: ::std::iter::IntoIterator<Item = i32>,
{
    fn construct(&self) -> f64 {
        let s = self.builder.get_start_point();
        let e = self.builder.get_end_point();

        s.into_iter()
            .zip(e.into_iter())
            .map(|(se, ee)| (se - ee).pow(2) as f64)
            .sum::<f64>()
            .sqrt()
    }
}