我的课堂笔记有代码实现HasArea
特征并打印区域,类似于Rust Book示例。教授的笔记如下:
trait HasArea<T> {
fn area(& self) -> T,
}
fn print<T: Display, S: HasArea<T>>(s: &S) {
println!("", s.area()); // println sth must impl Display trait
}
struct Circle {
x: T,
y: T,
r: T,
}
impl <T: Copy + Mul <Output = T>>
HasArea<T> for Circle<T>
{
fn area(&self) -> T {
self.r * self.r
}
}
将其与使用shape: T
作为输入的Rust Book进行比较:
trait HasArea {
fn area(&self) -> f64;
}
struct Circle {
x: f64,
y: f64,
radius: f64,
}
impl HasArea for Circle {
fn area(&self) -> f64 {
std::f64::consts::PI * (self.radius * self.radius)
}
}
fn print_area<T: HasArea>(shape: T) {
println!("This shape has an area of {}", shape.area());
}
fn main() {
let c = Circle {
x: 0.0f64,
y: 0.0f64,
radius: 1.0f64,
};
print_area(c);
}
我不确定为什么教授使用s: &S
,而Rust Book使用shape: T
。任何人都可以在实现通用函数时进行比较,我们何时将输入作为x: &T
传递,何时传递x: T
?
答案 0 :(得分:5)
在实施通用功能时,任何人都可以帮忙比较,我们何时将输入作为
x: &T
传递,何时传递x: T
?
与您接受x: Foo
和x: &Foo
的时间相同。获取x: Foo
会为x
提供所有权,并且(除非x
为Copy
),调用者将无法再次使用该功能。
在Rust Book示例中,print_area
取得circle
的所有权,因此您无法在circle
行之后使用print_area(circle);
。例如,以下内容:
fn main() {
// ...
print_area(c);
print_area(c);
}
抛出此错误:
error[E0382]: use of moved value: `c`
--> <anon>:29:16
|
28 | print_area(c);
| - value moved here
29 | print_area(c);
| ^ value used here after move
|
= note: move occurs because `c` has type `Circle`, which does not implement the `Copy` trait
根据我的经验,大多数时候你想要: &T
(就像你教授的注释一样)。只有当您需要结构的所有权时,才需要使用: T
。为简单起见,Rust Book可能使用: T
。
答案 1 :(得分:1)
这不是泛型问题,而是借贷和所有权问题。如果您希望将输入移入功能,则使用T
,否则如果您只想借用它,请使用&T
或&mut T
。