我如何解决所需的类型注释无法推断类型参数“T”的类型?编译此代码需要什么类型的注释?

How do i resolve type annotations needed cannot infer type for type parameter `T` ? What type annotation is needed to compile this code?

区块链结构定义,它定义了一个类型,我使用该类型

pub struct Blockchain<T = SledDb> {
    pub storage: T,
    pub chain: Vec<Block>,
    pub tip: Arc<RwLock<String>>,
    pub height: AtomicUsize,
    pub mempool: Mempool,
    pub wallet: Wallet,
    pub accounts: Account,
    pub stakes: Stake,
    pub validators: Validator,
}

此代码正在检查 stake 是否为 valid.The 用于挖掘块的代码,错误由 is_staking_valid 函数排除。我不知道它要求什么类型,因为我已经指定了一个。

impl<T: Storage> Blockchain<T> {
    pub fn is_staking_valid(
            balance: u64,
            difficulty: u32,
            timestamp: i64,
            prev_hash: &String,
            address: &String,
        ) -> bool {
            let base = BigUint::new(vec![2]);
            let balance_diff_mul = base.pow(256) * balance as u32;
            let balance_diff = balance_diff_mul / difficulty as u64;
    
            let data_str = format!("{}{}{}", prev_hash, address, timestamp.to_string());
            let sha256_hash = digest(data_str);
            let staking_hash = BigUint::parse_bytes(&sha256_hash.as_bytes(), 16).expect("msg");
    
            staking_hash <= balance_diff
        }
    pub fn mine_block(&mut self, data: &str) -> Option<Block> {

        if self.mempool.transactions.len() < 2 {
            info!("Skipping mining because no transaction in mempool");
            return None;
        }

        let balance = self
            .stakes
            .get_balance(&self.wallet.get_public_key())
            .clone();

        let difficulty = self.get_difficulty();
        info!("New block mining initialized with difficulty {}", difficulty);

        let timestamp = Utc::now().timestamp();
        let prev_hash = self.chain.last().unwrap().hash.clone();
        let address = self.wallet.get_public_key();


        if Blockchain::is_staking_valid(balance, difficulty, timestamp, &prev_hash, &address){

        let block = self.create_block(&data, timestamp);
        self.storage.update_blocks(&prev_hash, &block, self.height.load(Ordering::Relaxed));
        Some(block)
        } else {
           None
        }
    }
}
 

请在下面找到编译错误

error[E0282]: type annotations needed
   --> src/blocks/chain.rs:173:12
    |
173 |         if Blockchain::is_staking_valid(balance, difficulty, timestamp, &prev_hash, &address){
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T`

For more information about this error, try `rustc --explain E0282`.

最小化示例:

pub struct Blockchain<T> {
    pub storage: T,
}

impl<T> Blockchain<T> {
    pub fn is_staking_valid() {
        todo!()
    }
    pub fn mine_block(&mut self) {
        Blockchain::is_staking_valid();
    }
}

Playground

此错误的原因是 Blockchain::<T1>::is_staking_validBlockchain::<T2>::is_staking_valid 以及编译器所关注的两个独立的、完全不相关的函数。是的,它们有相同的代码,是的,它们将被优化器删除重复数据,但这并不一定是这种情况——例如,如果这个函数使用了一些在 T:[=33 上可用的关联项=]

trait Stakable {
    const IS_VALID: bool;
}
impl Stakable for () {
    const IS_VALID: bool = false;
}
impl Stakable for i32 {
    const IS_VALID: bool = true;
}

struct Blockchain<T> {
    pub _storage: T,
}

impl<T: Stakable> Blockchain<T> {
    fn validate() {
        if !T::IS_VALID {
            panic!("Type is not valid");
        }
    }
}

fn main() {
    // This panics - we catch this panic and show that it has indeed happened
    std::panic::catch_unwind(|| Blockchain::<()>::validate()).unwrap_err();
    // This executes successfully
    Blockchain::<i32>::validate();
}

Playground

由于可能存在歧义,编译器拒绝自行选择并强制您明确选择。


所以,您有几种可能的方法:

  • 使 is_staking_valid 成为自由函数,而不是 Blockchain 的关联函数。在这种情况下,它将无法依赖于 Blockchain 的类型参数,因此调用将是明确的。
  • 调用 Self::is_staking_valid 而不是 Blockchain::is_staking_valid。在这种情况下,Self 将被替换为 Blockchain::<T>T 取自当前执行的方法;这将再次解决歧义。
  • is_staking_valid 设为 Blockchain 上的方法,即使其接收 &self,并通过 self.is_staking_valid().
  • 调用它
  • 不推荐,但仍然可行,- 使 is_staking_valid 成为 Blockchain<T> 上的关联函数,用于 某些特定的 T,例如:
pub struct Blockchain<T> {
    pub storage: T,
}

impl Blockchain<()> {
    // Note - no free type parameters here!
    pub fn is_staking_valid() {
        todo!()
    }
}

impl<T> Blockchain<T> {
    pub fn mine_block(&mut self) {
        // Here, `Blockchain` is `Blockchain::<()>` - the method is set
        Blockchain::is_staking_valid();
    }
}