Rust泛型


當要建立多種形式的功能時,即,函式的引數可以接受多種型別的資料。 這可以通過泛型來實現。 泛型也稱為「引數多型」,其中多型是多重的,而變形是形式。

有兩種方法可以提供通用程式碼:

  • Option<T>
  • Result<T, E>

1.Option<T>:Rust標準庫提供Option,其中'T'是通用資料型別。 它提供了一種型別的泛型。

enum Option<T>  
{  
    Some(T),  
    None,  
}

在上面的例子中,enum是自定義型別,其中<T>是通用資料型別。 可以用任何資料型別替換T。下面來看看這幾個範例 :

let x : Option<i32> = Some(10);  // 'T' is of type i32.  
let x : Option<bool> = Some(true);  // 'T' is of type bool.  
let x : Option<f64> = Some(10.5); // 'T' is of type f64.  
let x : Option<char> = Some('b'); // 'T' is of type char.

在上面的例子中,觀察到'T'可以是任何型別,即i32boolf64char。 但是,如果左側的型別與右側的值不匹配,則會發生錯誤。 如下範例:

let x : Option<i32> = Some(10.8);

在上述情況下,左側的型別是i32,右側的值是f64型別。 因此,錯誤發生「型別不匹配」。

  1. Result <T,E>: Rust標準庫提供了另一種資料型別Result <T,E>,它是兩種型別的泛型,即T&E
enum Result<T,E>  
   {  
      OK(T),  
        Err(E),  
}

注意:不得不使用'T''E',可以使用任何大寫字母。

泛型函式

泛型可以在函式中使用,將泛型放在函式的簽名中,其中指定引數的資料型別和返回值。

  • 當函式包含型別為T的單個引數時。

語法

fn function_name<T>(x:T)   
// body of the function.

上面的語法包含兩部分:

  • <T> : 給定的函式是一種型別的泛型。
  • (x : T) : x 是型別 T

當函式包含多個相同型別的引數時。

fn function_name<T>(x:T, y:T)   
// body of the function.

當函式包含多個型別的引數時。

fn function_name<T,U>(x:T, y:U)  
// Body of the function.

完整程式碼 -

 fn main()  
{  
  let a = vec![1,2,3,4,5];  
  let b = vec![2.3,3.3,4.3,5.3];  
  let result = add(&a);  
  let result1 = add(&b);  
  println!("The value of result is {}",result);  
  println!("The value of result1 is {}",result1);  
}  

fn add<T>(list:&[T])->T  
{  
  let mut c =0;  
  for &item in list.iter()  
  {  
    c= c+item;  
  }  
}

結構定義

結構也可以使用<>運算子在一個或多個欄位中使用泛型型別引數。

語法:

struct structure_name<T>   
// Body of the structure.

在上面的語法中,在struct_name之後的尖括號中宣告泛型型別引數,然後可以在struct定義中使用泛型型別。

下面我們來看一個簡單的例子:

struct Value<T>  
{  
  a:T,  
  b:T,  
}  
fn main()  
{  
  let integer = Value{a:2,b:3};  
  let float = Value{a:7.8,b:12.3};  
  println!("integer values : {},{}",integer.a,integer.b);  
  println!("Float values :{},{}",float.a,float.b);  
}

執行上面範例程式碼,得到以下結果 -

integer values : 2,3
Float values : 7.8,12.3

在上面的範例中,Value <T>結構在一種型別上是通用的,而ab是相同型別的。建立兩個範例integerfloatInteger包含i32型別的值,float包含f64型別的值。

下面來看另一個簡單的例子。

struct Value<T>  
{  
  a:T,  
  b:T,  
}  
fn main()  
{  
  let c = Value{a:2,b:3.6};  
  println!("c values : {},{}",c.a,c.b);  
}

執行上面範例程式碼,得到以下結果:

在上面的範例中,Value <T>在一種型別上是通用的,而ab是相同型別的。建立了一個c的範例。c包含不同型別的值,即i32f64。 因此,Rust編譯器會丟擲「不匹配的錯誤」。

列舉定義

列舉也可以使用通用資料型別。Rust標準庫提供了Option <T>列舉,它包含通用資料型別。 Option <T>是一個列舉,其中T是通用資料型別。

  • Option<T>

它由兩個變體組成,即Some(T)None

其中Some(T)儲存型別T的值,None不包含任何值。

看看下面一段範例程式碼:

enum Option<T>  
{  
    Some(T),  
    None,  
}

在上面的例子中,Option是一個列舉,它在一個型別T上是通用的。 它由兩個變體Some(T)None組成。

Result<T, E> :可以建立多種型別的泛型,這可以通過Result <T,E>來實現。

enum Result<T,E>  
{  
    OK(T),  
    Err(E),  
}

在上面的例子中,Result <T,E>是一個列舉,它在兩種型別上是通用的,它由兩個變體組成,即OK(T)Err(E)

OK(T)保持型別T的值,而Err(E)保持型別E的值。

方法定義

可以在結構和列舉上實現這些方法。下來看看一個簡單的例子:

struct Program<T> {  
    a: T,  
    b: T,  
}  
impl<T> Program<T>   
{  
    fn a(&self) -> &T   
{  
       &self.a  
    }  
}

fn main() {  
    let p = Program{ a: 5, b: 10 };  

    println!("p.a() is {}", p.a());  
}

輸出結果如下 -

p.a() is 5

在上面的例子中,在Program <T>上實現了a方法,該方法返回對變數a中存在的資料的參照。在impl之後宣告了T,以指定在Program <T>上實現該方法。

解決歧義

Rust編譯器自動推斷通用引數。下面通過一個簡單的場景來理解:

Let mut v = Vec::new();   // creating a vector.  
v.push(10); // inserts integer value into the vector. Therefore, v is of i32 type.  
println!("{:?}", v); // prints the value of v.

在上面的例子中,將整數值插入向量中。 因此,Rust編譯器知道向量v的型別為i32

如果刪除第二行,現在程式碼如下所示 -

Let mut v = Vec::new();   // creating a vector.  
println!("{:?}", v); // prints the value of v.

上面的情況將丟擲「它無法推斷出T的型別」的錯誤。

可以通過兩種方式解決上述問題:

  1. 使用以下注釋:
let v : Vec<bool> = Vec::new();  
println!("{:?}",v) ;
  1. 使用'turbofish':: <>運算子系結泛型引數'T'
let v = Vec :: <bool> :: new();  
println!("{:?}",v) ;