Проблема с дженериками в реализации метода build_with_provider для EthereumCheckpointStorageBuilder

Вопрос или проблема

Я пытаюсь реализовать метод build_with_provider для обобщенной структуры EthereumCheckpointStorageBuilder. Как структура, так и метод используют один и тот же обобщенный ограничитель: M: Middleware + 'static.

Я хочу объявить обобщенный параметр M один раз и использовать его как в структуре, так и в методе. Однако я сталкиваюсь со следующей ошибкой:

метод `build_with_provider` не имеет параметров типа, но его объявление трейта имеет 1 параметр типа

Я попытался добавить отдельный обобщенный параметр P в метод build_with_provider, но это кажется избыточным и вызывает проблемы с From. Вот что я попробовал:

async fn build_with_provider<P>(
    ...
) -> Self::Output 
где
    P: Middleware + 'static,
    M: From<P>,

Есть ли более чистый способ объявить обобщенный параметр без его повторения, и как я могу решить эту ошибку?

Определения структуры и трейта

Ниже приведен соответствующий код:

// Определение структуры
pub struct EthereumCheckpointStorageBuilder<M> {
    _phantom: std::marker::PhantomData<M>,
}

// Реализация трейта
#[async_trait]
impl<M> BuildableWithProvider for EthereumCheckpointStorageBuilder<M>
где
    M: Middleware + 'static,
{
    type Output = EthereumCheckpointStorage<M>;
    const NEEDS_SIGNER: bool = true;

    async fn build_with_provider(
        &self,
        provider: M,
        conn: &ConnectionConf,
        locator: &ContractLocator,
    ) -> Self::Output {
        EthereumCheckpointStorage::new(Arc::new(provider), conn, locator)
    }
}

// Определение трейта
#[async_trait]
pub trait BuildableWithProvider {
    async fn build_with_provider<M>(
        &self,
        provider: M,
        conn: &ConnectionConf,
        locator: &ContractLocator,
    ) -> Self::Output
    где
        M: Middleware + 'static;
}

Ответ или решение

Проблема с обобщениями в методе build_with_provider для EthereumCheckpointStorageBuilder

При разработке системы, связанной с Ethereum, вы столкнулись с сложностями в реализации метода build_with_provider для обобщенной структуры EthereumCheckpointStorageBuilder. Давайте подробно разберем вашу проблему, выявим причины ошибок и предложим оптимальное решение.

Присутствующая Проблема

При попытке реализации метода у вас возникает ошибка:

method `build_with_provider` has 0 type parameters but its trait declaration has 1 type parameter

Это указывает на то, что компилятор Rust не может сопоставить параметры обобщения для метода, потому что вы пытаетесь объявить параметр M в трейте, хотя он уже объявлен в структуре.

Обзор Кода

Ваша структура и реализация трейта выглядят следующим образом:

  1. Определение структуры:

    pub struct EthereumCheckpointStorageBuilder<M> {
        _phantom: std::marker::PhantomData<M>,
    }
  2. Реализация трейта:

    #[async_trait]
    impl<M> BuildableWithProvider for EthereumCheckpointStorageBuilder<M>
    where
        M: Middleware + 'static,
    {
        type Output = EthereumCheckpointStorage<M>;
        const NEEDS_SIGNER: bool = true;
    
        async fn build_with_provider(
            &self,
            provider: M,
            conn: &ConnectionConf,
            locator: &ContractLocator,
        ) -> Self::Output {
            EthereumCheckpointStorage::new(Arc::new(provider), conn, locator)
        }
    }
  3. Определение трейта:

    #[async_trait]
    pub trait BuildableWithProvider {
        async fn build_with_provider<M>(
            &self,
            provider: M,
            conn: &ConnectionConf,
            locator: &ContractLocator,
        ) -> Self::Output
        where
            M: Middleware + 'static;
    }

Решение Проблемы

Чтобы устранить данную ошибку и упростить реализацию, вам необходимо уменьшить количество дублирующихся параметров обобщения. Вместо того, чтобы вновь объявлять M в методе трейта, можно использовать уже существующий параметр обобщения M. Вот исправленный код:

  1. Определение трейта с использованием обобщенного параметра M:

    #[async_trait]
    pub trait BuildableWithProvider<M>: Sized
    where
        M: Middleware + 'static,
    {
        async fn build_with_provider(
            &self,
            provider: M,
            conn: &ConnectionConf,
            locator: &ContractLocator,
        ) -> Self::Output;
    }
  2. Реализация трейта остается неизменной:

    #[async_trait]
    impl<M> BuildableWithProvider<M> for EthereumCheckpointStorageBuilder<M>
    where
        M: Middleware + 'static,
    {
        type Output = EthereumCheckpointStorage<M>;
        const NEEDS_SIGNER: bool = true;
    
        async fn build_with_provider(
            &self,
            provider: M,
            conn: &ConnectionConf,
            locator: &ContractLocator,
        ) -> Self::Output {
            EthereumCheckpointStorage::new(Arc::new(provider), conn, locator)
        }
    }

Заключение

В результате, теперь метод build_with_provider будет использовать параметр обобщения M, объявленный в трейте, который уже соответствует параметру в вашей структуре EthereumCheckpointStorageBuilder. Это решение не только устраняет ошибку компиляции, но и делает ваш код более чистым и понятным.

Рекомендуется также регулярно проверять, чтобы ваши реализации трейтов и структуры использовали единообразные обобщенные параметры, что способствует легкости поддержки и расширяемости вашего кода.

Оцените материал
Добавить комментарий

Капча загружается...