如何解压缩多态向量中包含的元素?

fad*_*bee 3 boxing vector rust

在阅读了"属于特征的对象的向量"的答案之后,看起来Rust会自动取消装箱.是这样的吗?

我的代码没有编译,我不明白该答案的代码如何编译.

解包多态向量元素的正确方法是什么,包含盒装特征?

我读过通过实例锈Box文档,我不能看到像这样的任何方法unbox().

我的代码是:

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)
    }
}

struct Square {
    x: f64,
    y: f64,
    side: f64,
}

impl HasArea for Square {
    fn area(&self) -> f64 {
        self.side * self.side
    }
}

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,
    };

    let s = Square {
        x: 0.0f64,
        y: 0.0f64,
        side: 1.0f64,
    };

    print_area(c);
    print_area(s);

    let vec: Vec<Box<HasArea>> = Vec::new();
    vec.push(Box::new(c));
    vec.push(Box::new(s));

    for x in vec {
        print_area(x)
    }
}
Run Code Online (Sandbox Code Playgroud)

我的错误是:

   Compiling rustgraph v0.1.0 (file:///home/chris/lunch/rustgraph)
error[E0277]: the trait bound `Box<HasArea>: HasArea` is not satisfied
  --> src/main.rs:54:9
   |
54 |         print_area(x)
   |         ^^^^^^^^^^ the trait `HasArea` is not implemented for `Box<HasArea>`
   |
   = note: required by `print_area`
Run Code Online (Sandbox Code Playgroud)

cor*_*ump 8

您可以取消引用它print_area(*x),但由于其他原因它不起作用:参数的Sized界限print_area.您的函数需要知道其参数的大小.

您的代码中还有其他问题:您正在尝试推入不可变向量,并且您尝试将移动的值设置为空.这些都是在您使用它之后移动的print_area().

我的观点是,制作print_area一个采用不可变引用的方法会更容易.这将按预期工作.

trait HasArea {
    fn area(&self) -> f64;
    fn print_area(&self) {
        println!("This shape has area of {}", self.area());
    }
}

struct Circle {
    x: f64,
    y: f64,
    radius: f64,
}

impl HasArea for Circle {
    fn area(&self) -> f64 {
        std::f64::consts::PI * (self.radius * self.radius)
    }
}

struct Square {
    x: f64,
    y: f64,
    side: f64,
}

impl HasArea for Square {
    fn area(&self) -> f64 {
        self.side * self.side
    }
}

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,
    };

    let s = Square {
        x: 0.0f64,
        y: 0.0f64,
        side: 1.0f64,
    };

    c.print_area();
    s.print_area();

    let mut vec: Vec<Box<HasArea>> = Vec::new();
    vec.push(Box::new(c));
    vec.push(Box::new(s));

    for x in vec {
        x.print_area();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 它只是方法调用的自动解引用,这就是为什么rust没有`obj.method()`和`pointer-> method()`语法,你可以在这里阅读:https://doc.rust-lang.org /book/deref-coercions.html (2认同)

She*_*ter 5

要回答您的直接问题:

如何拆箱包含在多态向量中的元素?

不能。一旦某些东西被装箱并擦除了具体类型,就是这样。ABox<SomeTrait>不能变回 a SomeConcreteType,因为没有人知道具体类型是什么。


解决代码中的问题...再次查看错误信息:

特征界限Box<HasArea>: HasArea不满足

那是因为对特征(或特征框)的引用没有实现该特征

为了让你的程序像你最初编写的那样编译和运行,你只需要为 box 实现 trait,我们也可以做引用:

impl<T: ?Sized> HasArea for Box<T>
    where T: HasArea
{
    fn area(&self) -> f64 { (**self).area() }    
}

impl<'a, T: ?Sized> HasArea for &'a T
    where T: HasArea
{
    fn area(&self) -> f64 { (**self).area() }    
}
Run Code Online (Sandbox Code Playgroud)

这允许您的固定主程序运行:

fn main() {
    let c = Circle {
        x: 0.0f64,
        y: 0.0f64,
        radius: 1.0f64,
    };

    let s = Square {
        x: 0.0f64,
        y: 0.0f64,
        side: 1.0f64,
    };

    print_area(&c);
    print_area(&s);

    let vec: Vec<Box<HasArea>> = vec![Box::new(c), Box::new(s)];

    for x in vec {
        print_area(x)
    }
}
Run Code Online (Sandbox Code Playgroud)

在这里,我们传递的参考c,并sprint_area,为了避免过户。我们还使用vec!宏以更少的仪式来构造向量。