Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.3k views
in Technique[技术] by (71.8m points)

rust - Do I have to use a usize to access elements of a vector?

I have a 2D vector that rejects indexing using i32 values, but works if I cast those values using as usize:

#[derive(Clone)]
struct Color;

struct Pixel {
    color: Color,
}

fn shooting_star(p: &mut Vec<Vec<Pixel>>, x: i32, y: i32, w: i32, h: i32, c: Color) {
    for i in x..=w {
        for j in y..=h {
            p[i][j].color = c.clone();
        }
    }
}

fn main() {}

When I compile, I get the error message

error[E0277]: the trait bound `i32: std::slice::SliceIndex<[std::vec::Vec<Pixel>]>` is not satisfied
  --> src/main.rs:11:13
   |
11 |             p[i][j].color = c.clone();
   |             ^^^^ slice indices are of type `usize` or ranges of `usize`
   |
   = help: the trait `std::slice::SliceIndex<[std::vec::Vec<Pixel>]>` is not implemented for `i32`
   = note: required because of the requirements on the impl of `std::ops::Index<i32>` for `std::vec::Vec<std::vec::Vec<Pixel>>`

If I change the code to have

p[i as usize][j as usize].color = c.clone();

Then everything works fine. However, this feels like it would be a really bizarre choice with no reason not to be handled by the Vec type.

In the documentation, there are plenty of examples like

assert_eq!(vec[0], 1);

By my understanding, if a plain number with no decimal is by default an i32, then there's no reason using an i32 to index shouldn't work.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Unlike Java, C# or even C++, numeric literals in Rust do not have a fixed type. The numeric type of a literal is usually inferred by the compiler, or explicitly stated using a suffix (0usize, 0.0f64, and so on). In that regard, the type of the 0 literal in assert_eq!(vec[0], 1); is inferred to be a usize, since Rust allows Vec indexing by numbers of type usize only.

As for the rationale behind using usize as the indexing type: a usize is equivalent to a word in the target architecture. Thus, a usize can refer to the index/address of all possible memory locations for the computer the program is running on. Thus, the maximum possible length of a vector is the maximum possible value that can be contained in a isize (isize::MAX == usize::MAX / 2). Using usize sizes and indices for a Vec prevents the creation and usage of a vector larger than the available memory itself.

Furthermore, the usage of an unsigned integer just large enough to refer all possible memory locations allows the removal of two dynamic checks, one, the supplied size/index is non-negative (if isize was used, this check would have to be implemented manually), and two, creating a vector or dereferencing a value of a vector will not cause the computer to run out of memory. However, the latter is guaranteed only when the type stored in the vector fits into one word.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...