Как определить псевдоним локального типа функции для параметров типа функции (или связанных с ними типов)? - PullRequest
0 голосов
/ 06 февраля 2019

У меня есть общая функция foo с некоторыми чертами комплексного характера:

use std::ops::Index;

// This trait is just as an example
trait Float {
    const PI: Self;
    fn from_f32(v: f32) -> Self;
}
// impl Float for f32, f64 ...

fn foo<C>(container: &C)
where
    C: Index<u32>,
    <C as Index<u32>>::Output: Float,
{
    // ...
}

Теперь мне нужно использовать тип <C as Index<u32>>::Output внутри функции связка (например, чтобы получить π через ::PI или сказать ::from_f32(3.0)).Но этот тип долго печатать вручную и делает весь код очень многословным и трудным для чтения.( Примечание : в моем реальном коде фактический тип еще длиннее и уродлив.)

Чтобы решить эту проблему, я попытался создать псевдоним локального типа функции:

// Inside of `foo`:
type Floaty = <C as Index<u32>>::Output;

Но это приводит к этой ошибке:

error[E0401]: can't use type parameters from outer function
  --> src/lib.rs:16:20
   |
10 | fn foo<C>(container: &C)
   |    --- - type variable from outer function
   |    |
   |    try adding a local type parameter in this method instead
...
16 |     type Floaty = <C as Index<u32>>::Output;
   |                    ^ use of type variable from outer function

Таким образом, как и другие элементы, псевдонимы type также обрабатываются независимо от того, находятся они в функции или нет.Не имея хороших идей, я попытался написать макрос, который расширяется до типа:

// Inside of `foo`:
macro_rules! Floaty {
    () => { <C as Index<u32>>::Output };
}

Floaty!()::PI;    // errors

Хотя у меня был частичный успех с этим (Floaty!() допустим в некоторых контекстах типа), эта последняя строка содержит ошибкис:

error: expected one of `.`, `;`, `?`, `}`, or an operator, found `::`
  --> src/lib.rs:20:14
   |
20 |     Floaty!()::PI;    // errors
   |              ^^ expected one of `.`, `;`, `?`, `}`, or an operator here

error[E0575]: expected method or associated constant, found associated type `Index::Output`
  --> src/lib.rs:17:17
   |
17 |         () => { <C as Index<u32>>::Output };
   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
...
20 |     Floaty!()::PI;    // errors
   |     --------- in this macro invocation
   |
   = note: can't use a type alias as a constructor

Ни одна из моих попыток не сработала полностью. Можно ли не писать полное имя типа каждый раз?

Ответы [ 2 ]

0 голосов
/ 06 февраля 2019

У дизеля есть подобная "проблема", и они решили ее путем определения псевдонимов нефункционального типа .Мне нравится это решение, потому что вы также можете использовать псевдоним для очистки границ своих черт:

type Floaty<C> = <C as Index<u32>>::Output;

fn foo<C>(container: &C)
where
    C: Index<u32>,
    Floaty<C>: Float,
{
    let p = Floaty::<C>::PI;
    // ...
}

Обратите внимание, что вам придется изменить черту Float, чтобы она равнялась Sized, чтобына самом деле запустить этот код.

0 голосов
/ 06 февраля 2019

Единственный способ, которым я видел это, - добавить тип в качестве другого параметра типа в функцию.

fn foo<F, C>(container: &C)
where
    F: Float,
    C: Index<u32, Output = F>,
{
    let pi = F::PI;
    // ...
}

Обычно это не вызывает проблем с выводом типа, поскольку будет только одинтип F, который работает для данного C (по крайней мере, в этом примере), но он определенно использует шум, так как для указания типа F вы также должны поместить заполнитель для C и наоборот.

...