使用thiserror转换Ethers-rs的MiddlewareError遇编译错误求助
问题解决:Ethers-rs MiddlewareError 转自定义错误的编译冲突
错误原因分析
第一个编译错误
你遇到的第一个错误是因为?操作符需要将Middleware核心错误类型M::Error(比如Provider的RPC调用错误)转换为自定义错误CFFMError<M>,但初始代码仅处理了gas_oracle::MiddlewareError<M>(gas oracle模块专属的错误类型,包含M::Error等子错误),没有实现M::Error到CFFMError<M>的转换,因此编译器要求补充该转换逻辑。
第二个编译错误
当你尝试为M::Error添加#[from]属性生成自动转换时,thiserror会生成From<M::Error> for CFFMError<M>的实现。但标准库存在全局默认实现impl<T> From<T> for T,如果M::Error恰好等于CFFMError<M>(比如自定义Middleware将错误类型设为CFFMError<M>),就会出现重复的From实现,触发冲突。
解决方案
不要使用#[from]自动生成M::Error的转换,改为手动实现From<M::Error> for CFFMError<M>,既满足转换需求,又避免和标准库的默认实现冲突:
use ethers::prelude::gas_oracle::MiddlewareError; use ethers::prelude::{AbiError, ContractError}; use ethers::providers::{Middleware, ProviderError}; use thiserror::Error; use tokio::task::JoinError; use uniswap_v3_math::error::UniswapV3MathError; #[derive(Error, Debug)] pub enum CFFMError<M> where M: Middleware, { // 处理gas oracle模块的MiddlewareError #[error("Gas oracle middleware error: {0}")] GasOracleMiddlewareError(#[from] MiddlewareError<M>), // 处理Middleware核心错误(比如Provider的RPC错误) #[error("Core middleware error: {0}")] CoreMiddlewareError(M::Error), // 其他自定义错误变体 #[error("ABI error: {0}")] AbiError(#[from] AbiError), #[error("Contract interaction error: {0}")] ContractError(#[from] ContractError<M>), #[error("Tokio task join error: {0}")] JoinError(#[from] JoinError), #[error("Uniswap V3 math error: {0}")] UniswapV3MathError(#[from] UniswapV3MathError), } // 手动实现M::Error到CFFMError<M>的转换 impl<M> From<M::Error> for CFFMError<M> where M: Middleware, { fn from(err: M::Error) -> Self { CFFMError::CoreMiddlewareError(err) } }
补充说明
- 注意区分
gas_oracle::MiddlewareError<M>和M::Error:前者是gas oracle操作时的包装错误,后者是Middleware自身的核心错误类型(比如ProviderError)。 - 手动实现
Fromtrait可以完全控制转换逻辑,避免自动生成带来的潜在冲突,同时让错误变体的职责更清晰。
内容的提问来源于stack exchange,提问作者0xKitsune
相关产品推荐
相关产品推荐

