How do tuples and arrays work compared to Lua's tables?

Some differences:

  • In Lua, an empty table allocates memory on the heap (try print{} in Lua). In Rust, an empty Vec or empty HashMap do not allocate memory on the heap (until you push elements into it). This is particularly relevant in Lua because it imposes work on the garbage collection mechanism there.
  • Tuples and arrays in Rust have a fixed number of elements once created, while tables in Lua may always grow. (Rust requires a Vec or HashMap if you want to change the number of elements later.)
  • When Lua tables contain holes (i.e. intermediate nil values for positive integer keys smaller than the maximum used integer key), then certain operations don't work properly anymore; in particular the length operator # in Lua becomes unspecified. In Rust, you may not arbitrarily set any value to None unless you make the contained type Option<T> instead of T. In that case, None is an ordinary value which doesn't cause the Vec, HashMap, array, or tuple to behave any different.
  • Lua's tables serve many purposes:
    • named arguments (what would often be a builder pattern in Rust),
    • growable sorted lists of elements of the same type (what would be a Vec<T> in Rust, where T is the type of each element),
    • growable sorted lists of elements of different types (what could be a Vec<dyn Trt> in Rust, where Trt is a trait each element's type must implement)
    • fixed number of elements of the same type (what would be an array in Rust, though sometimes you would deliberately use a Vec instead),
    • fixed number of elements of different but fixed types (what would be a tuple in Rust),
    • mapping strings to values (what would be a HashMap<String, _>, HashMap<&str, _>, or HashMap<Cow<'_, str>, _> in Rust),
    • mapping tables to values (for which I cannot imagine a Rust equivalent),

Note that you can emulate the behavior of retrieving infinite nils (as in Lua) also in Rust:

fn main() {
    let vec = vec![Some(15), None, Some(30)];
    assert_eq!(vec.get(0).cloned().flatten(), Some(15));
    assert_eq!(vec.get(1).cloned().flatten(), None);
    assert_eq!(vec.get(2).cloned().flatten(), Some(30));
    assert_eq!(vec.get(3).cloned().flatten(), None);
    assert_eq!(vec.get(4).cloned().flatten(), None);
    assert_eq!(vec.get(5).cloned().flatten(), None);
}

(Playground)