本文概述
当我们要创建多种形式的函数时, 即函数的参数可以接受多种类型的数据。这可以通过泛型来实现。泛型也称为”参数多态性”, 其中poly是多个, 而morph是形式。
提供通用代码有两种方法:
- 选项<T>
- 结果<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”可以是任何类型, 即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);
}
输出
在上面的示例中, Value <T>结构在一种类型上是通用的, 并且a和b是同一类型。我们创建一个’c’的实例。 ‘c’包含不同类型的值, 即i32和f64。因此, Rust编译器将引发”不匹配的错误”。
枚举定义
枚举也可以使用通用数据类型。Rust标准库提供了Option <T>枚举, 用于保存通用数据类型。 Option <T>是一个枚举, 其中” T”是通用数据类型。
- 选项<T>
它由两个变体组成, 即Some(T)和None。
其中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) ;