3 ms·
Why does Rust choose not to provide `for` comprehensions?
- kibwen 3y agoAmusingly, this actually does exist in Rust, via the `std::array::from_fn` function (which I don't see mentioned in the OP): let my_arr = [1, 2, 3, 4, 5]; let new_arr = std::array::from_fn(|i| my_arr[i] + 1); assert_eq!([2, 3, 4, 5, 6], new_arr); And yes, this is producing a fixed-size array on the stack; in this case the length of the array is being inferred based on the type provided in the assertion. https://doc.rust-lang.org/std/array/fn.from_fn.html https://doc.rust-lang.org/std/array/fn.from_fn.html
- crznp 3y agoThat's interesting, though the type inference seems like spooky action at a distance there: removing an assertion can break code. I suppose it gives you a way to specify the length in the examples (below), but it seems more ergonomic to take it from the original array. let bool_arr = core::array::from_fn::<_, 5, _>(|i| i % 2 == 0);
- _nalply 3y agoOr declare the type of bool_arr.
- kibwen 3y ago> seems like spooky action at a distance Note that this inference is static, and the compiler would tell you if it didn't have something concrete to infer the type from. The type inference is also limited to the function body, so removing the assertion could only ever cause an effect in that single function.
- veber-alex 3y agoOr just array::map https://doc.rust-lang.org/nightly/std/primitive.array.html#method.map https://doc.rust-lang.org/nightly/std/primitive.array.html#m...
- happytoexplain 3y ago> the length of the array is being inferred based on the type provided in the assertion Wow! I hate that with an amount of emotion that surprised me! Does Rust do this kind of look-ahead inference a lot (specifically for deciding what the result shape/type is for a statement)?
- kibwen 3y ago> Does Rust do this kind of look-ahead inference a lot Yes, but it's important to note that type inference in Rust is function-local. Furthermore, crucially, Rust requires types to be explicitly specified at function boundaries. Altogether this means that you (and the compiler) don't need to look farther than the function signature to figure out a given type. This means that you can do stuff like this: let mut foo = HashMap::new(); foo.insert("bar", true); Despite the fact that HashMap is a generic type, nowhere do we need to specify that this particular instance has string keys and Boolean values, because the type of the map is inferred from its usage. In languages with only statement-local type inference, you'd need to specify the type of the elements at the point of construction.
- happytoexplain 3y agoThis isn't so bad except in the case where a developer puts off the resolving statement until later in the function, though I imagine (hope) there is almost never a legitimate reason to do that. Is it theoretically possible to split the resolution into two lines? Then, as a reader, it might not always be obvious at what point the type is fully resolved. E.g (pseudocode, and also it makes no practical sense since you would have populated it before interrogating it). let mut foo = HashMap::new(); print(foo.containsKey("bar")); // here we've resolved the key type print(foo.containsValue(true)); // here we've resolved the value type
- metabagel 3y ago[flagged]
- deleted 3y ago[deleted]
- deleted 3y ago[deleted]
- someguy101010 3y agoI personally prefer the following style instead of comprehensions let my_arr = [1, 2, 3, 4, 5]; my_arr.iter().map(|x| x + 1).for_each( |item| println!("The Value of this item is {item}") ); the map statement allows for one liners, like list comprehensions, with the added benefit of semantics like being able to chain operations into pipelines.
- justincredible 3y ago[dead]