A modern programming language wouldn't be complete without closures, and Dart is no exception. To oversimplify this, a closure is a function that is saved to a variable that can be called later. They are often used for callbacks, such as when the user taps a button or when the app receives data from a network call.
We showed two ways to define closures in this recipe:
- Function prototypes
- typedefs
The easiest and most maintainable way to work with closures is with the typedef keyword. This is especially true if you are planning on reusing the same closure type multiple times; then, using typedefs will make your code more succinct:
typedef NumberGetter = int Function();
This defines a closure type called NumberGetter, which is a function that is expected to return an integer:
int powerOfTwo(NumberGetter getter) {
return getter() * getter();
}
The closure type is then used in this function, which will call the closure twice and then multiply the result:
final getFour = () => 4;
final squared = powerOfTwo(getFour);
In this line, we call the function and provide our closure, which returns the number 4. This code also uses the fat arrow syntax, which allows you to write any function that takes up a single line without braces. For single-line functions, you can use the arrow syntax, =>, instead of brackets.
The getFour line without the arrow is equivalent to writing the following:
final getFour = () {
return 4;
};
// this is the same as: final getFour = () => 4;
Arrow functions are very helpful for removing unneeded syntax, but they should only be used for simple statements. For complex functions, you should use the block function syntax.
Closures are probably one of the most cognitively difficult programming concepts. It may seem awkward to use them at first, but the only way for it to become natural is to practice using them several times.