fn main() {
let t = (||print!("h"), ||println!("hello world"));
}
It compiles. After I changed this code to use array,
fn main() {
let t = [||print!("h"), ||println!("hello world")];
}
it also compiles. So which has better performance?
fn main() {
let t = (||print!("h"), ||println!("hello world"));
}
It compiles. After I changed this code to use array,
fn main() {
let t = [||print!("h"), ||println!("hello world")];
}
it also compiles. So which has better performance?
The performance is the same.
Doesn’t matter
In general the performance between using tuples and arrays should always be comparable (in cases where both can be used in the same manner).
In your concrete case, the main
function does absolutely nothing in either case, and will be optimized away completely.
On rust.godbolt.org, if you add -O
to flags, you can check how optimized code looks like.
In this case both functions are exactly identical — entirely empty.
Wait a minute, what is going on here? How are you getting those closures into that array? I thought this was impossible because all elements of an array should be the same type but "no two closures, even if identical, have the same type" as the compiler says.
I'm now curious why this:
let mut closures = vec![];
closures.push(|| println!("Hello "));
closures.push(|| println!("world!"));
fails to compile with error:
closures.push(|| println!("world!"));
| ---- ^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure
...
note: no two closures, even if identical, have the same type
However I can get those same two closures into arrays and vectors, including pushing into vectors, with this:
// An array of closures.
let mut closures = [|| print!("Hello "), || println!("world!")];
for closure in &closures {
closure();
}
// Which we can assign to
closures[0] = || print!("xxx ");
closures[1] = || println!("yyy");
for closure in &closures {
closure();
}
// A Vector of closures assigned from an array.
let mut closures = vec![];
closures = [|| print!("Hello "), || println!("world!")].to_vec();
for closure in &closures {
closure();
}
// Which we can push into
closures.push(|| print!("xxx"));
closures.push(|| println!("yyy"));
for closure in &closures {
closure();
}
// A Vector initialized from an array closures.
let mut closures = Vec::from([|| print!("Hello "), || println!("world!")]);
for closure in &closures {
closure();
}
// Which we can also push() into
closures.push(|| print!("xxx "));
closures.push(|| println!("yyy"));
for closure in &closures {
closure();
}
Which compiles and runs just fine.
In the OP they're coercing to function pointers. With the nonworking vector, the compiler infers a closure type instead. You could fix it with a type annotation.
So I can:
let mut closures: Vec<fn()> = vec![];
closures.push(|| println!("Hello "));
closures.push(|| println!("world!"));
for closure in &closures {
closure();
}
Well I never. Sneaky things these coercion's. Thanks.
Tuples and arrays are essentially identical in performance. Use whichever best fits the problem you're trying to solve.
Well, except that Hash
on arrays is slightly slower than on tuples.
This line is too small.
Well… if you don’t Hash
the thing, then the difference won’t matter.
In case you’re interested why it’s “slower” for arrays: when hashing an array, the size of the error is fed into the hash function alongside the elements, whereas tuples only feed the elements. This is technically slower, since more data is hashed, but also, realistically, it’s not a lot slower, especially for longer arrays, or arrays with large[1] items, the difference becomes relatively small.
The reason why this is done is so that hashing of arrays can stay compatible with hashing of slices as required for this Borrow
implementation; this allows a &[T]
to be used to index into a HashMap<[T; 32], _>
for example. And hashing of slices needs to include length information because slices are not fixed-length.
in terms of amount of information that needs to be hashed ↩︎
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.