Rust泛型图解和用法

本文概述

当我们要创建多种形式的函数时, 即函数的参数可以接受多种类型的数据。这可以通过泛型来实现。泛型也称为”参数多态性”, 其中poly是多个, 而morph是形式。

提供通用代码有两种方法:

  • 选项<T>
  • 结果<T, E>
Rust泛型

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”可以是任何类型, 即i32, bool, f64或char。但是, 如果左侧的类型和右侧的值不匹配, 则会发生错误。让我们来看一下:

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

在上述情况下, 左侧的类型为i32, 右侧的值为f64类型。因此, 错误发生”类型不匹配”。

2. 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;
  }
  c}

结构定义

结构还可以使用<>运算符在一个或多个字段中使用通用类型参数。

句法:

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

在以上语法中, 我们在structure_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>结构在一种类型上是通用的, 并且a和b是同一类型。我们创建两个实例integer和float。整数包含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);
 }

输出

Rust泛型

在上面的示例中, Value <T>结构在一种类型上是通用的, 并且a和b是同一类型。我们创建一个’c’的实例。 ‘c’包含不同类型的值, 即i32和f64。因此, Rust编译器将引发”不匹配的错误”。

枚举定义

枚举也可以使用通用数据类型。Rust标准库提供了Option <T>枚举, 用于保存通用数据类型。 Option <T>是一个枚举, 其中” T”是通用数据类型。

  • 选项<T>

它由两个变体组成, 即Some(T)和None。

Rust泛型

其中Some(T)保留T类型的值, 而None不包含任何值。

我们看看吧:

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

在上述情况下, Option是一个枚举, 在一个类型” T”上是通用的。它由两个变量Some(T)和None组成。

  • 结果<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中存在的数据的引用。

我们在暗示之后声明了” 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) ;

2.我们可以使用’turbofish’:: <>运算符来绑定通用参数’T’:

let v = Vec :: <bool> :: new();
println!("{:?}", v) ;

微信公众号
手机浏览(小程序)
0
分享到:
没有账号? 忘记密码?