What is the canonical way to do the following in Rust?
let s: Shape;
if something {
s = Circle::new();
} else {
s = Square::new();
}
The way that seems most obvious to me:
use std::env;
trait Shape {
fn area(&self) -> f32;
}
struct Circle {
rad: f32,
}
impl Circle {
pub fn new() -> Circle {
Circle {
rad: 5.0,
}
}
}
impl Shape for Circle {
fn area(&self) -> f32 {
self.rad * self.rad * 3.14159
}
}
struct Square {
len: f32,
}
impl Square {
pub fn new() -> Square {
Square {
len: 5.0,
}
}
}
impl Shape for Square {
fn area(&self) -> f32 {
self.len * self.len
}
}
fn main() {
let args: Vec<String> = env::args().collect();
let s: Shape;
if args.len() > 1 {
s = Circle::new();
} else {
s = Square::new();
}
println!("Area: {}", s.area());
}
Results in:
error[E0277]: the trait bound `Shape: std::marker::Sized` is not satisfied
--> src/main.rs:46:9
|
46 | let s: Shape;
| ^ `Shape` does not have a constant size known at compile-time
|
In general, Circle and Square may indeed have different sizes, so we really can't know what size 's' will be at compile time.
This question Polymorphism in Rust would seem to indicate that you need to write a wrapper struct (called ShapeStruct in this example), which takes a generic and where you break out each function that the trait implements like:
struct ShapeStruct<T> {
shape: T,
}
impl<T: Shape> ShapeStruct<T> {
fn area(&self) -> f32 {
self.shape.area()
}
}
But this would result in a lot of boilerplate - each function that the trait declares would need a break out like 'area' is broken out above. Is there no better way?