如何拆箱包含在多态向量中的元素?
How to unbox elements contained in polymorphic vectors?
看完this answer to "Vector of objects belonging to a trait",Rust好像是自动拆箱的。是这样吗?
我的代码无法编译,我不明白答案的代码如何编译。
将多态向量的元素拆箱的正确方法是什么,其中包含已装箱的特征?
我读过 Rust by Example and the Box
documentation 但我看不到任何看起来像 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)
}
}
我的错误是:
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`
您可以像 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();
}
}
After reading it looks like Rust does automatic unboxing. Is this the case?
并不像您想象的那样自动。事实上,您正在寻找 unbox
方法,而 Box<T>
为目标 T
实现 Deref
。这意味着您应该调用 as_ref()
或依赖 Deref
强制转换。请注意,T
对于未确定大小的类型是不可能的,并且由于您依赖于多态类型,因此使用者函数将必须接受引用。
我冒昧地修复了 main
和 print_area
以使其工作。该向量也被错误地声明为不可变。
fn print_area<T: HasArea + ?Sized>(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 mut vec: Vec<Box<HasArea>> = Vec::new();
vec.push(Box::new(c));
vec.push(Box::new(s));
for x in vec {
print_area(&*x)
}
}
作为 E_net4 建议的替代方案,您可以使用带有引用的 Vec
来代替装箱您的特征:
fn print_area<T: HasArea+?Sized>(shape: &T) {
println!("This shape has an area of {}", shape.area());
}
let mut vec: Vec<&HasArea> = Vec::new();
vec.push(&c);
vec.push(&s);
for x in vec {
print_area(x)
}
回答您的直接问题:
How to unbox elements contained in polymorphic vectors?
你不能。一旦装箱并删除了具体类型,就是这样。 Box<SomeTrait>
不能变回 SomeConcreteType
,因为没有人知道具体类型是什么。
解决代码中的问题...再次查看错误信息:
the trait bound Box<HasArea>: HasArea
is not satisfied
那是因为对特征的引用(或特征框)!
为了让你的程序像你最初写的那样编译和运行,你只需要实现盒子的特征,我们不妨也做参考:
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() }
}
这允许您的固定主线 运行:
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)
}
}
在这里,我们将 c
和 s
的引用传递给 print_area
,以避免转移所有权。我们还使用 vec!
宏以更少的仪式构造向量。
看完this answer to "Vector of objects belonging to a trait",Rust好像是自动拆箱的。是这样吗?
我的代码无法编译,我不明白答案的代码如何编译。
将多态向量的元素拆箱的正确方法是什么,其中包含已装箱的特征?
我读过 Rust by Example and the Box
documentation 但我看不到任何看起来像 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)
}
}
我的错误是:
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`
您可以像 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();
}
}
After reading it looks like Rust does automatic unboxing. Is this the case?
并不像您想象的那样自动。事实上,您正在寻找 unbox
方法,而 Box<T>
为目标 T
实现 Deref
。这意味着您应该调用 as_ref()
或依赖 Deref
强制转换。请注意,T
对于未确定大小的类型是不可能的,并且由于您依赖于多态类型,因此使用者函数将必须接受引用。
我冒昧地修复了 main
和 print_area
以使其工作。该向量也被错误地声明为不可变。
fn print_area<T: HasArea + ?Sized>(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 mut vec: Vec<Box<HasArea>> = Vec::new();
vec.push(Box::new(c));
vec.push(Box::new(s));
for x in vec {
print_area(&*x)
}
}
作为 E_net4 建议的替代方案,您可以使用带有引用的 Vec
来代替装箱您的特征:
fn print_area<T: HasArea+?Sized>(shape: &T) {
println!("This shape has an area of {}", shape.area());
}
let mut vec: Vec<&HasArea> = Vec::new();
vec.push(&c);
vec.push(&s);
for x in vec {
print_area(x)
}
回答您的直接问题:
How to unbox elements contained in polymorphic vectors?
你不能。一旦装箱并删除了具体类型,就是这样。 Box<SomeTrait>
不能变回 SomeConcreteType
,因为没有人知道具体类型是什么。
解决代码中的问题...再次查看错误信息:
the trait bound
Box<HasArea>: HasArea
is not satisfied
那是因为对特征的引用(或特征框)
为了让你的程序像你最初写的那样编译和运行,你只需要实现盒子的特征,我们不妨也做参考:
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() }
}
这允许您的固定主线 运行:
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)
}
}
在这里,我们将 c
和 s
的引用传递给 print_area
,以避免转移所有权。我们还使用 vec!
宏以更少的仪式构造向量。