什么时候在Rust通用函数中将输入作为T或& T?

时间:2016-11-01 07:28:40

标签: generics rust

我的课堂笔记有代码实现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

2 个答案:

答案 0 :(得分:5)

  

在实施通用功能时,任何人都可以帮忙比较,我们何时将输入作为x: &T传递,何时传递x: T

与您接受x: Foox: &Foo的时间相同。获取x: Foo会为x提供所有权,并且(除非xCopy),调用者将无法再次使用该功能。

在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

Relevant book section