同样也可以用 <> 语法来定义结构体,它包含一个或多个泛型参数类型字段。
如何定义和使用一个可以存放任何类型的 x 和 y 坐标值的结构体 Point:
x: T,
y: T,
}
fn main() {
let integer = Point { x: 5, y: 10 };
let float = Point { x: 1.0, y: 4.0 };
}
其语法类似于函数定义中使用泛型。首先,必须在结构体名称后面的尖括号中声明泛型参数的名称。接着在结构体定义中可以指定具体数据类型的位置使用泛型类型。
注意 Point 的定义中只使用了一个泛型类型,这个定义表明结构体 Point 对于一些类型 T 是泛型的,而且字段 x 和 y 都是相同类型的,无论它具体是何类型。
x: T,
y: T,
}
fn main() {
let wont_work = Point { x: 5, y: 4.0 };
}
在这个例子中,当把整型值 5 赋值给 x 时,就告诉了编译器这个 Point 实例中的泛型 T 是整型的。接着指定 y 为 4.0,它被定义为与 x 相同类型,就会得到一个像这样的类型不匹配错误:
Compiling chapter10 v0.1.0 (file:///projects/chapter10)
error[E0308]: mismatched types
--> src/main.rs:7:38
|
7 | let wont_work = Point { x: 5, y: 4.0 };
| ^^^ expected integer, found floating-point number
For more information about this error, try `rustc --explain E0308`.
error: could not compile `chapter10` due to previous error
如果想要定义一个 x 和 y 可以有不同类型且仍然是泛型的 Point 结构体,我们可以使用多个泛型类型参数。我们修改 Point 的定义为拥有两个泛型类型 T 和 U。其中字段 x 是 T 类型的,而字段 y 是 U 类型的:
x: T,
y: U,
}
fn main() {
let both_integer = Point { x: 5, y: 10 };
let both_float = Point { x: 1.0, y: 4.0 };
let integer_and_float = Point { x: 5, y: 4.0 };
}
枚举定义中的泛型
和结构体类似,枚举也可以在成员中存放泛型数据类型。第六章我们曾用过标准库提供的 Option 枚举,这里再回顾一下:
Some(T),
None,
}
现在这个定义应该更容易理解了。如你所见 Option 是一个拥有泛型 T 的枚举,它有两个成员:Some,它存放了一个类型 T 的值,和不存在任何值的None。通过 Option 枚举可以表达有一个可能的值的抽象概念,同时因为 Option 是泛型的,无论这个可能的值是什么类型都可以使用这个抽象。
枚举也可以拥有多个泛型类型。第九章使用过的 Result 枚举定义就是一个这样的例子:
Ok(T),
Err(E),
}
Result 枚举有两个泛型类型,T 和 E。Result 有两个成员:Ok,它存放一个类型 T 的值,而 Err 则存放一个类型 E 的值。这个定义使得 Result 枚举能很方便的表达任何可能成功(返回 T 类型的值)也可能失败(返回 E 类型的值)的操作。当成功打开
文件的时候,T 对应的是 std:: fs :: File 类型;而当打开文件出现问题时,E 的值则是 std:: io :: Error 类型。
当你意识到代码中定义了多个结构体或枚举,它们不一样的地方只是其中的值的类型的时候,不妨通过泛型类型来避免重复。