Метод с именем len не найден для типа:: Введите текущую область - PullRequest
0 голосов
/ 17 мая 2018

Я хочу сообщить 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 голосов
/ 17 мая 2018

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

Ваш цикл может быть переписан для более идиоматического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()
    }
}
0 голосов
/ 17 мая 2018

Я хочу сообщить 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; в определении черты.

...