Trait(特征)
derive(起源)
编译器可以使用#[derive]属性提供一些trait的基本实现。声明属性后的trait实现,依然可以自己重新方法。
The following is a list of derivable traits:
- Comparison traits: Eq, PartialEq, Ord, PartialOrd.
- Clone, to create T from &T via a copy.
- Copy, to give a type ‘copy semantics’ instead of ‘move semantics’.
- Hash, to compute a hash from &T.
- Default, to create an empty instance of a data type.
- Debug, to format a value using the {:?} formatter.
returning traits with dyn
编译器需要明确的知道返回值需要占用多少字节的空间,所以每一个函数的返回类型必须是具体类型。
当需要返回一个trait的具体实现类时,由于不同实现可能占用不同大小的空间,所以必能直接使用trait作为返回值。
我们可以通过返回一个Box,来绕过这样的限制。由于box是指向heap中的一块区域的引用,所以它拥有固定的长度。
rust总是试图明确的确定要在heap上分配多大内存,所以,如果你试图返回一个point-to-trait-on-heap的值时,需要通过dyn关键字。
1 | fn random_animal(random_number: f64) -> Box<dyn Animal> { |
操作符重载
rust中操作符重载,非常简单,只需要实现具体的trait就可以了。
rust中的操作符相关的trait都在core::ops包中。
Drop
Drop trait只有一个drop方法,它将在对象作用域结束的时候被自动调用。
当需要返回一个类型时返回 impl Trait
impl可以用来返回trait和闭包类型
1 | fn combine_vecs( |
1 | // Returns a function that adds `y` to its input |
- 函数声明的返回值
-> Box
-> impl Trait
有啥区别?
动态分发和静态分发
Clone Trait
当我们赋值或者调用函数时,默认是会发生所有权转移。有时候我们并不想让所有权发生转移,那么我们可以实现Clone Trait。
super trait
rust中并没有继承
的概念,但是,我们可以定义一个trait是其他trait的超集
1 | trait Person { |
消除重叠trait中的“二义性”
我们可能实现多个trait,这些trait中可能会有重复的方法,怎么去消除“二义性”
- 由于对不同trait的实现是在不同的impl块中,所以,很容易对重复的方法实现。
- 当调用重复的方法时,需要用as关键字明确的指定要调用那个trait中的方法。
1
2
3
4let username = <Form as UsernameWidget>::get(&form);
assert_eq!("rustacean".to_owned(), username);
let age = <Form as AgeWidget>::get(&form);
assert_eq!(28, age);