Kiểu Generic là kiểu dữ liệu cho phép chúng ta chỉ viết code một lần mà có thể sử dụng cho nhiều kiểu dữ liệu khác nhau. Nếu bạn đã từng lập trình Java hay C++ thì nó cũng tương tự như kiểu Generic trong Java và template trong C++ vậy.
Chúng ta có thể áp dụng kiểu generic vào struct và hàm trong Rust. Để các struct và hàm có thể hiểu được kiểu generic thì chúng ta phải thêm 3 kí tự sau đây vào sau tên của struct hoặc hàm:
<T>
Đầu tiên là dấu bé hơn <
, rồi đến kí tự T
, rồi đến dấu lớn hơn >
. Chúng ta cũng có thể sử dụng kí tự khác ngoài T
. Ví dụ:
struct MyGenericStruct<T> {
value: T
}
fn main() {
let year: MyGenericStruct<i32> = MyGenericType { value: 2017 };
let pi: MyGenericStruct<f64> = MyGenericType { value: 3.1415 };
let site: MyGenericStruct<&str>= MyGenericType { value: "phocode.com" };
}
Trong ví dụ trên chúng ta định nghĩa kiểu MyGenericStruct
có một thuộc tính là value
có kiểu là generic.
Khi tạo các đối tượng generic thì chúng ta khai báo như struct bình thường và đưa kèm kiểu dữ liệu cụ thể mà chúng ta muốn sử dụng, chẳng hạn ở trên chúng ta tạo 3 đối tượng MyGenericStruct
với 3 kiểu dữ liệu khác nhau là i32
, f64
và str
. Giá trị mà chúng ta khởi tạo cũng phải khớp với kiểu đã khai báo, nếu không Rust sẽ báo lỗi.
Khi sử dụng với hàm cũng vậy, chúng ta khai báo <T> trước tên hàm, bên trong nếu chúng ta nhận vào tham số là kiểu generic thì chúng ta cũng khai báo tên kiểu với <T>. Nếu hàm trả về giá trị của kiểu generic thì chúng ta chỉ cần ghi T là dược, ví dụ:
struct MyGenericType<T> {
value: T
}
fn getValue<T>(param: MyGenericType<T>) -> T {
return param.value;
}
fn main() {
let year: MyGenericType<i32> = MyGenericType { value: 2017 };
let pi: MyGenericType<f64> = MyGenericType { value: 3.1415 };
let site: MyGenericType<&str> = MyGenericType { value: "phocode.com" };
println!("Year: {:?}", getValue(year));
println!("PI = {:?}", getValue(pi));
println!("Site name: {:?}", getValue(site));
}
Trong đoạn code trên chúng ta định nghĩa hàm getValue()
nhận vào tham số có kiểu MyGenericStruct
tên là param
, hàm này cũng trả về giá trị kiểu T
, bên trong chúng ta cho trả về thuộc tính value
của tham số.
Year: 2017 PI = 3.1415 Site name: "phocode.com"
Kiểu Option
và Result
mà chúng ta đã học cũng là kiểu generic, định nghĩa của kiểu Option
như sau:
enum Option<T> {
Some(T),
None
}
Như bạn thấy thì kiểu Option
có thể nhận 1 trong 2 giá trị là một đối tượng Some
hoặc None
. Và đối tượng Some
ở đây nhận một kiểu generic nên chúng ta có thể truyền vào giá trị gì cũng được, ví dụ:
fn main() {
let year: Option<i32> = Some(2017);
let none: Option<f64> = None;
let site: Option<&str> = Some("phocode.com");
println!("Year: {:?}", year);
println!("None: {:?}", none);
println!("Site name: {:?}", site);
}
Do đó kiểu Option là một kiểu dữ liệu generic được xây dựng sẵn khá mạnh mẽ.
Year: Some(2017) None: None Site name: Some("phocode.com")