Why this programm one not work?

Hello people! subj...

struct Rectangle {
    width: u32,
    height: u32,
}

struct RectangleNumber (&Rectangle, &Rectangle, &Rectangle);

impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }

    fn can_hold(&self, other: &Rectangle) -> bool {
        self.width > other.width && self.height > other.height
    }
}

// impl Rectangle_number {
//     fn print_area(&self) {
//         for i in 0..2 {
//             println! ("The area of rect{} is {}", i+1, )
//         }
//     }
// }


fn main() {

    let rect1 = Rectangle {
        width: 30,
        height: 50,
    };

    let rect2 = Rectangle {
        width: 10,
        height: 40,
    };

    let rect3 = Rectangle {
        width: 60,
        height: 45,
    };

    let rect = RectangleNumber (&rect1, &rect2, &rect3);

    println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2));
    println!("Can rect1 hold rect3? {}", rect1.can_hold(&rect3));
    
    for i in 0..2 {
        
        println! ("The area of rect{} is {}.", &i+1, rect[i].area)
                    
    }
}

Is there a question?

1 Like

You get two types of error message with this code:

error[E0106]: missing lifetime specifier
 --> src/main.rs:6:25
  |
6 | struct RectangleNumber (&Rectangle, &Rectangle, &Rectangle);
  |                         ^ expected named lifetime parameter
  |
help: consider introducing a named lifetime parameter
  |
6 | struct RectangleNumber<'a> (&'a Rectangle, &Rectangle, &Rectangle);
  |                       ++++   ++

This is because you have a reference inside a structure, where there's no way to have a self contained check of the lifetime of what's being referenced. Rust is suggesting the change that would make this work, but in general it's just a bad idea to do this, because you can't use these types across methods very well.

It also has:

error[E0608]: cannot index into a value of type `RectangleNumber`
  --> src/main.rs:51:54
   |
51 |         println! ("The area of rect{} is {}.", &i+1, rect[i].area)
   |                                                      ^^^^^^^

This is because rect is not a collection that can be indexed, but a "tuple struct", a structure where the fields have no name. That is, unlike Javascript, foo.0 is not the same thing as foo[0].

You can fix both these issues by using a Vec or array, so you have something to index, or by implementing Index for RectangleNumber, depending on what the situation is. Here, RectangleNumber is essentially the type [&Rectangle; 3], which you can create and use a such:

struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }

    fn can_hold(&self, other: &Rectangle) -> bool {
        self.width > other.width && self.height > other.height
    }
}


fn main() {

    let rect1 = Rectangle {
        width: 30,
        height: 50,
    };

    let rect2 = Rectangle {
        width: 10,
        height: 40,
    };

    let rect3 = Rectangle {
        width: 60,
        height: 45,
    };

    let rects = [&rect1, &rect2, &rect3];

    println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2));
    println!("Can rect1 hold rect3? {}", rect1.can_hold(&rect3));
    
    for (i, rect) in rects.iter().enumerate() {
        
        println! ("The area of rect{} is {}.", &i+1, rect.area()) 
                    
    }
}

Note at the end the use of for (i, rect) in rects.iter().enumerate(), which both gives you the index and the item at the same time, no matter how many items there are. Don't worry about the details of that yet, normally you would just use for rect in rects or similar.

1 Like

Ok, I have modify it and it did some work

struct Rectangle {
    width: u32,
    height: u32,
}

struct RectangleNumber<'a> (&'a Rectangle, &'a Rectangle, &'a Rectangle);

impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }

    fn can_hold(&self, other: &Rectangle) -> bool {
        self.width > other.width && self.height > other.height
    }
}

fn main() {

    let rect1 = Rectangle {
        width: 30,
        height: 50,
    };

    let rect2 = Rectangle {
        width: 10,
        height: 40,
    };

    let rect3 = Rectangle {
        width: 60,
        height: 45,
    };

    let rect = RectangleNumber (&rect1, &rect2, &rect3);

    println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2));
    println!("Can rect1 hold rect3? {}", rect1.can_hold(&rect3));

    // for i in 0..2 {
    // println!("Area of rect{} is {}", &i+1, rect.i.area());
    // }
    
    println!("Area of rect{} is {}", 0+1, rect.1.area());
}

I don't understand why it not works with the loop "for". Sorry I am beginner and don't understand many things...

That is because rect.i would access a named field called i and not the specific field of the tuple struct. The struct you defined could also have named fields, like this:

struct RectangleNumber<'a> {
    first: &'a Rectangle,
    second: &'a Rectangle,
    third: &'a Rectangle
}

In general, it is not possible to iterate over the fields of a struct or tuple because they might have different types. As @simonbuchan suggested, a fixed-size array will probably be a better option.

2 Likes

Thank you very much it is working now!