Sized and using traits as sized objects - rust

struct Point { x: f64, y: f64 }
struct Circle { center: Point, radius: f64 }
struct Square { lowerLeftCorner: Point, side: f64 }
trait ShapeVisitor {
fn visit_circle(&mut self, c: &Circle);
fn visit_square(&mut self, c: &Square);
}
trait Shape {
fn accept<V: ShapeVisitor>(&self, sv: &mut V);
}
impl Shape for Circle {
fn accept<V: ShapeVisitor>(&self, sv: &mut V) {
sv.visit_circle(self);
}
}
impl Shape for Square {
fn accept<V: ShapeVisitor>(&self, sv: &mut V) {
sv.visit_square(self);
}
}
So here's a method that computes the total area:
fn area(shapes: Vec<Box<dyn Shape>>) -> f64 {
struct AreaCalculator {
area: f64,
}
impl ShapeVisitor for AreaCalculator {
fn visit_circle(&mut self, c: &Circle) {
self.area += std::f64::consts::PI * c.radius * c.radius;
}
fn visit_square(&mut self, r: &Square) {
self.area += r.side * r.side;
}
}
let mut calculator = AreaCalculator { area: 0.0 };
for shape in shapes {
(*shape).accept(calculator);
}
calculator.area
}
And here's an example program
fn main() {
let mut shapes: Vec<Box<dyn Shape>> = Vec::new();
let p = Point { x: 0.0, y: 0.0 };
let circle = Circle { center: p, radius: 12.0 };
shapes.push(Box::new(circle));
let area = compute_area(shapes);
println!("Area {:?}", area);
}
Here's the error report:
error[E0038]: the trait `Shape` cannot be made into an object
--> visitor.rs:26:25
|
26 | fn compute_area(shapes: Vec<Box<dyn Shape>>) -> f64 {
| ^^^^^^^^^^^^^^^^^^^ `Shape` cannot be made into an object
|
= help: consider moving `accept` to another trait
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> visitor.rs:11:8
|
10 | trait Shape {
| ----- this trait cannot be made into an object...
11 | fn accept<V: ShapeVisitor>(&self, sv: &mut V);
| ^^^^^^ ...because method `accept` has generic type parameters
error: aborting due to previous error
Is there a simple way to rectify it?

In order to be able to create a trait object, the trait must be object safe. But your Shape is not object safe - it has generic type parameters. Removing the type parameters solves the issue:
#[derive(Copy, Clone)]
struct Point {
x: f64,
y: f64,
}
struct Circle {
center: Point,
radius: f64,
}
struct Square {
lowerLeftCorner: Point,
side: f64,
}
trait ShapeVisitor {
fn visit_circle(&mut self, c: &Circle);
fn visit_square(&mut self, c: &Square);
}
trait Shape {
fn accept(&self, sv: &mut dyn ShapeVisitor);
}
impl Shape for Circle {
fn accept(&self, sv: &mut dyn ShapeVisitor) {
sv.visit_circle(self);
}
}
impl Shape for Square {
fn accept(&self, sv: &mut dyn ShapeVisitor) {
sv.visit_square(self);
}
}
fn area(shapes: Vec<Box<dyn Shape>>) -> f64 {
struct AreaCalculator {
area: f64,
}
impl ShapeVisitor for AreaCalculator {
fn visit_circle(&mut self, c: &Circle) {
self.area += std::f64::consts::PI * c.radius * c.radius;
}
fn visit_square(&mut self, r: &Square) {
self.area += r.side * r.side;
}
}
let mut calculator = AreaCalculator { area: 0.0 };
for shape in shapes {
shape.accept(&mut calculator);
}
calculator.area
}
fn main() {
let mut shapes: Vec<Box<dyn Shape>> = Vec::new();
let p = Point { x: 0.0, y: 0.0 };
let circle = Circle {
center: p,
radius: 1.0,
};
shapes.push(Box::new(circle));
shapes.push(Box::new(Square {
lowerLeftCorner: p,
side: 10.0,
}));
let area = area(shapes);
println!("Area {:?}", area);
}

Related

Value referencing data owned by the current function

Here's my code:
struct Something<'a> {
val: u32,
another: &'a AnotherThing,
}
struct AnotherThing {
val: u32,
}
impl Default for AnotherThing {
fn default() -> Self {
Self {
val: 2,
}
}
}
trait Anything {
fn new(val: u32) -> Self;
}
impl Anything for Something<'_> {
fn new(val: u32) -> Self {
Self {
val,
another: &AnotherThing::default(),
}
}
}
fn main() {
let _ = Something::new(1);
}
It doesn't compile because:
Compiling playground v0.0.1 (/playground)
error[E0515]: cannot return value referencing temporary value
--> src/main.rs:24:9
|
24 | / Self {
25 | | val,
26 | | another: &AnotherThing::default(),
| | ----------------------- temporary value created here
27 | | }
| |_________^ returns a value referencing data owned by the current function
I understand the problem but I don't know how to fix it. If it's not possible to use the Default trait for this case, how can I deal with the function ownership. Below a simpler example:
struct Something<'a> {
val: u32,
another: &'a AnotherThing,
}
struct AnotherThing {
val: u32,
}
trait Anything {
fn new(val: u32) -> Self;
}
impl Anything for Something<'_> {
fn new(val: u32) -> Self {
let at = AnotherThing { val : 2 };
Self {
val,
another: &at,
}
}
}
fn main() {
let _ = Something::new(1);
}
If I had another: &AnotherThing { val : 2 } instead of another: &at it would work. If I want the another attribute to be a reference and get the value from a function, how can I do it?
You can do like this
#[derive(Default)]
struct Something<'a> {
val: u32,
another: &'a AnotherThing,
}
struct AnotherThing {
val: u32,
}
impl<'a> Default for &'a AnotherThing {
fn default() -> &'a AnotherThing {
&AnotherThing {
val: 3,
}
}
}
trait Anything {
fn new(val: u32) -> Self;
}
impl Anything for Something<'_> {
fn new(val: u32) -> Self {
Self {
val,
..Default::default()
}
}
}
Another option is to create a const item, of which you can create a reference with 'static lifetime, thus binding to any 'a:
struct Something<'a> {
val: u32,
another: &'a AnotherThing,
}
struct AnotherThing {
val: u32,
}
const ANOTHER_THING_DEFAULT: AnotherThing = AnotherThing { val: 3 };
trait Anything {
fn new(val: u32) -> Self;
}
impl Anything for Something<'_> {
fn new(val: u32) -> Self {
Self {
val,
another: &ANOTHER_THING_DEFAULT,
}
}
}

How to impl conversion between different inner types?

This yields E0119:
#![feature(destructuring_assignment)]
pub struct Point<T> {
pub x: T,
pub y: T,
}
impl<F, T: From<F>> From<Point<F>> for Point<T> {
fn from<F>(f: Point<F>) -> Self {
let Point { mut x, mut y } = f;
(x, y) = (T::from(x), T::from(y));
Self { x, y }
}
}
The implementation conflict is in std::convert::From for T:
impl<T> From<T> for T {
fn from(t: T) -> T {
t
}
}
I assume there isn't a way to work around this so much as there may be more rust-idiomatic approach to the problem of converting between inner types, or even a more idiomatic understanding of what the "problem" is.
You can implement it as a normal method that takes a closure and then pass it the From::from trait method when you call it. Or even specialize it for types that implement From<T>:
#[derive(Debug)]
pub struct Point<T> {
pub x: T,
pub y: T,
}
impl<T> Point<T> {
pub fn map<U>(self, mut f: impl FnMut(T) -> U) -> Point<U> {
let Point { x, y } = self;
Point {
x: f(x),
y: f(y),
}
}
pub fn map_into<U: From<T>>(self) -> Point<U> {
let Point { x, y } = self;
Point {
x: U::from(x),
y: U::from(y),
}
}
}
fn main() {
let point_i16 = Point { x: 6i16, y: 3200i16 };
let point_f32: Point<f32> = point_i16.map(From::from);
let point_f64: Point<f64> = point_f32.map_into();
println!("{:?}", point_f64); // Point { x: 6.0, y: 3200.0 }
}

How do I downgrade an Rc<RefCell<T>> into a Weak<T>?

After adding a RefCell to the inside struct, I don't know how to have a reference to only the Rc value.
In other words, I'm creating an Rc<RefCell<T>> but I only need the Rc<T> to be able to downgrade into a Weak.
use std::{
cell::RefCell,
fmt,
rc::{Rc, Weak},
};
#[derive(Debug)]
struct Field {
i: u8,
y: u8,
}
impl Field {
pub fn new() -> Self {
Self { i: 8, y: 6 }
}
}
#[derive(Debug)]
pub struct Parent {
field_1: Field,
child: RefCell<Option<Child>>,
}
impl Parent {
pub fn new() -> Rc<RefCell<Self>> {
let n = Rc::new(RefCell::new(Self {
field_1: Field::new(),
child: RefCell::new(None),
}));
*n.borrow_mut().child.borrow_mut() = Some(Child::new(&n));
n
}
pub fn modify(&mut self) {
self.field_1.i = 9;
}
pub fn to_string(&self) -> String {
format!(
"{:?} {}",
self.field_1,
self.child.borrow().as_ref().unwrap()
)
}
}
#[derive(Debug)]
pub struct Child {
parent: Weak<Parent>,
field_2: Field,
}
impl Child {
pub fn new(parent: &Rc<Parent>) -> Self {
Self {
parent: Rc::downgrade(parent),
field_2: Field::new(),
}
}
}
impl fmt::Display for Child {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.parent.upgrade().unwrap().field_1.i == 1 {
write!(f, "set: {:?}", self.field_2)
} else {
write!(f, "not set {:?}", self.field_2)
}
}
}
fn main() {
let mut parent = Parent::new();
parent.borrow_mut().modify();
println!("{}", parent.borrow().to_string());
}
Error:
Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
--> src/main.rs:32:62
|
32 | *n.borrow_mut().child.borrow_mut() = Some(Child::new(&n));
| ^^ expected struct `Parent`, found struct `std::cell::RefCell`
|
= note: expected reference `&std::rc::Rc<Parent>`
found reference `&std::rc::Rc<std::cell::RefCell<Parent>>`
I realize that the data structure itself might be the problem, but I currently can't think of a improvement.

Do Rust builder patterns have to use redundant struct code?

I was looking at the Method syntax section of the Rust documentation and came across an example of the builder pattern. The CircleBuilder struct in the example below is an exact duplicate of the Circle struct. It seems like this redundant code violates the usual norms of programming.
I understand why the example created a new struct, because the creator did not want to implement the builder methods against the original Circle struct. That is fine, but is there a way to rewrite this example so that there is no redundancy--yet still keeping the nice builder interface in the main() function intact?
I tried to create an empty struct or a struct with just one throwaway element, but that did not work.
struct Circle {
x: f64,
y: f64,
radius: f64,
}
impl Circle {
fn area(&self) -> f64 {
std::f64::consts::PI * (self.radius * self.radius)
}
}
struct CircleBuilder {
x: f64,
y: f64,
radius: f64,
}
impl CircleBuilder {
fn new() -> CircleBuilder {
CircleBuilder { x: 0.0, y: 0.0, radius: 1.0, }
}
fn x(&mut self, coordinate: f64) -> &mut CircleBuilder {
self.x = coordinate;
self
}
fn y(&mut self, coordinate: f64) -> &mut CircleBuilder {
self.y = coordinate;
self
}
fn radius(&mut self, radius: f64) -> &mut CircleBuilder {
self.radius = radius;
self
}
fn finalize(&self) -> Circle {
Circle { x: self.x, y: self.y, radius: self.radius }
}
}
fn main() {
let c = CircleBuilder::new()
.x(1.0)
.y(2.0)
.radius(2.0)
.finalize();
println!("area: {}", c.area());
println!("x: {}", c.x);
println!("y: {}", c.y);
}
Do Rust builder patterns have to use redundant struct code?
No. But sometimes they might. For example, consider if we wanted to have special logic (or even just complicated logic) around our constructor:
/// Width must always be greater than height!
struct HorizontalEllipse {
width: f64,
height: f64,
}
impl HorizontalEllipse {
fn area(&self) -> f64 {
std::f64::consts::PI * (self.width / 2.0) * (self.height / 2.0)
}
}
struct HorizontalEllipseBuilder {
width: f64,
height: f64,
}
impl HorizontalEllipseBuilder {
fn new() -> HorizontalEllipseBuilder {
HorizontalEllipseBuilder {
width: 0.0,
height: 0.0,
}
}
fn width(&mut self, width: f64) -> &mut HorizontalEllipseBuilder {
self.width = width;
self
}
fn height(&mut self, height: f64) -> &mut HorizontalEllipseBuilder {
self.height = height;
self
}
fn finalize(&self) -> Result<HorizontalEllipse, String> {
let HorizontalEllipseBuilder { height, width } = *self;
if height >= width {
Err("This is not horizontal".into())
} else {
Ok(HorizontalEllipse { width, height })
}
}
}
fn main() {
let c = HorizontalEllipseBuilder::new()
.width(1.0)
.height(2.0)
.finalize()
.expect("not a valid ellipse");
println!("area: {}", c.area());
println!("width: {}", c.width);
println!("height: {}", c.height);
}
Now a HorizontalEllipse knows that it is always true that width > height. We've moved that check from many potential places (each method) to one, the constructor. We then moved the constructor to a new type because it was complicated (not really, but truly complicated examples are usually... complicated).
Many builders I've seen also have "enhanced" types of the real object:
#[derive(Debug)]
struct Person {
name: String,
}
#[derive(Debug, Default)]
struct PersonBuilder {
name: Option<String>,
}
impl PersonBuilder {
fn name(self, name: &str) -> Self {
PersonBuilder { name: Some(name.into()), ..self }
}
fn build(self) -> Person {
Person {
name: self.name.unwrap_or_else(|| "Stefani Joanne Angelina Germanotta".into()),
}
}
}
fn main() {
let person = PersonBuilder::default().build();
println!("{:?}", person);
let person = PersonBuilder::default().name("krishnab").build();
println!("{:?}", person);
}
You don't see that in the book's example because it's trying to be simpler and not involve ownership concerns.
This seems like the sort of thing a macro might be able to do. A quick search found the derive_builder and builder_macro crates which seem to implement this functionality.

Is there a way to perform an index access to an instance of a struct?

Is there a way to perform an index access to an instance of a struct like this:
struct MyStruct {
// ...
}
impl MyStruct {
// ...
}
fn main() {
let s = MyStruct::new();
s["something"] = 533; // This is what I need
}
You can use the Index and IndexMut traits.
use std::ops::{Index, IndexMut};
struct Foo {
x: i32,
y: i32,
}
impl Index<&'_ str> for Foo {
type Output = i32;
fn index(&self, s: &str) -> &i32 {
match s {
"x" => &self.x,
"y" => &self.y,
_ => panic!("unknown field: {}", s),
}
}
}
impl IndexMut<&'_ str> for Foo {
fn index_mut(&mut self, s: &str) -> &mut i32 {
match s {
"x" => &mut self.x,
"y" => &mut self.y,
_ => panic!("unknown field: {}", s),
}
}
}
fn main() {
let mut foo = Foo { x: 0, y: 0 };
foo["y"] += 2;
println!("x: {}", foo["x"]);
println!("y: {}", foo["y"]);
}
It prints:
x: 0
y: 2
You want to use the Index trait (and its pair IndexMut):
use std::ops::Index;
#[derive(Copy, Clone)]
struct Foo;
struct Bar;
impl Index<Bar> for Foo {
type Output = Foo;
fn index<'a>(&'a self, _index: Bar) -> &'a Foo {
println!("Indexing!");
self
}
}
fn main() {
Foo[Bar];
}

Resources