2017-10-20 41 views
0

這與my earlier question有關使得模冪泛型方法成爲可能。現在我已經來到了下面的代碼:爲什麼二元運算符的這個結果需要適當的生命週期?

fn powm<T>(fbase: &T, exponent: &T, modulus: &T) -> T 
where 
    T: Mul<T, Output = T> 
     + From<u8> 
     + PartialEq<T> 
     + Rem<T, Output = T> 
     + Copy 
     + for<'a> Rem<&'a T, Output = T> 
     + Clone 
     + PartialOrd<T> 
     + ShrAssign<T>, 
    for<'a> &'a T: PartialEq<T> + Rem<&'a T, Output = T>, 
{ 
    if modulus == T::from(1) { 
     T::from(0) 
    } else { 
     let mut result = T::from(1); 
     let mut base = fbase % modulus; 
     let mut exp = exponent.clone(); 
     while exp > T::from(0) { 
      if exp % T::from(2) == T::from(1) { 
       result = (result * base) % modulus; 
      } 
      exp >>= T::from(1); 
      base = (base * base) % modulus; 
     } 
     result 
    } 
} 

這是我的理解是通過定義特徵約束where for<'a> &'a T: Rem<&'a T, Output=T>是可以理解的,我可以用模運算%&'a T類型的兩個操作數,然後將結果將是類型T。不過,我得到以下錯誤:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements 
    --> src/main.rs:20:30 
    | 
20 |   let mut base = fbase % modulus; 
    |       ^
    | 
note: first, the lifetime cannot outlive the anonymous lifetime #3 defined on the function body at 3:1... 
    --> src/main.rs:3:1 
    | 
3 |/fn powm<T>(fbase: &T, exponent: &T, modulus: &T) -> T 
4 | | where 
5 | |  T: Mul<T, Output = T> 
6 | |   + From<u8> 
... | 
30 | |  } 
31 | | } 
    | |_^ 
note: ...so that reference does not outlive borrowed content 
    --> src/main.rs:20:32 
    | 
20 |   let mut base = fbase % modulus; 
    |        ^^^^^^^ 
note: but, the lifetime must be valid for the anonymous lifetime #1 defined on the function body at 3:1... 
    --> src/main.rs:3:1 
    | 
3 |/fn powm<T>(fbase: &T, exponent: &T, modulus: &T) -> T 
4 | | where 
5 | |  T: Mul<T, Output = T> 
6 | |   + From<u8> 
... | 
30 | |  } 
31 | | } 
    | |_^ 
note: ...so that types are compatible (expected std::ops::Rem, found std::ops::Rem<&T>) 
    --> src/main.rs:20:30 
    | 
20 |   let mut base = fbase % modulus; 
    |       ^

如果我通過

let mut base = fbase.clone() % modulus; 

更換有問題的代碼行的代碼不工作,我不明白爲什麼我需要擺在首位,如果克隆我可以使用模運算符來返回類型爲T的「新鮮」元素。我需要修改我的特質範圍嗎?爲什麼這會出錯?

+1

FWIW,我可能只是[避免參考](https://play.integer32.com/?gist=9889ac1244f40e9bb180c6292895401c&version=stable)。 – Shepmaster

回答

3

編程時,學習如何創建Minimal, Complete, and Verifiable example (MCVE)是非常有用的。這使您可以忽略不相關的細節,並專注於問題的核心。

舉一個例子,代碼整個BLOB可降低到:

use std::ops::Rem; 

fn powm<T>(fbase: &T, modulus: &T) 
where 
    for<'a> &'a T: Rem<&'a T, Output = T>, 
{ 
    fbase % modulus; 
} 

fn main() {} 

一旦你有一個MCVE,可以使排列來探究。例如,我們可以刪除the lifetime elision

fn powm<'a, 'b, T>(fbase: &'a T, modulus: &'b T) 
where 
    for<'x> &'x T: Rem<&'x T, Output = T>, 
{ 
    fbase % modulus; 
} 

現在我們開始看到的東西:什麼是所有三代人之間的關係?那麼,真的沒有一個。如果我們製作一個會發生什麼?

  • 如果說輸入的引用可以被統一到同一個 壽命,它的工作原理:

    fn powm<'a, T>(fbase: &'a T, modulus: &'a T) 
    
  • 如果說'b會超越'a,它的工作原理:

    fn powm<'a, 'b: 'a, T>(fbase: &'a T, modulus: &'b T) 
    
  • 如果我們說我們可以在運營商有兩個不同的生命週期,它的工作原理如下:

    for<'x, 'y> &'x T: Rem<&'y T, Output = T>, 
    

有關,如果我們在調用點戳是什麼?

  • 如果我們直接調用Rem::rem方法,它的工作原理:

    Rem::rem(fbase, modulus); 
    
  • 如果我們取消引用,並重新引用,它的工作原理:

    &*fbase % &*modulus; 
    

我不t知道究竟是原因爲何不起作用 - 概念上兩個輸入引用應該能夠統一到一個生命週期。有可能有一個推斷要麼不能或不正在發生,但我不知道它。

與Rust編譯器開發者的進一步討論導致an issue,因爲它看起來不太合適。這個問題現在已經是resolved,理論上應該在Rust 1.23中可用。

相關問題