A tour of the Dart language
This page shows you how to use each major Dart feature, from variables and operators to classes and libraries, with the assumption that you already know how to program in another language. For a briefer, less complete introduction to the language, see the language samples page.
To learn more about Dart’s core libraries, see the library tour. Whenever you want more details about a language feature, consult the Dart language specification.
Note: You can play with most of Dart’s language features using DartPad (learn more). Open DartPad.
This page uses embedded DartPads to display some of the examples. If you see empty boxes instead of DartPads, go to the DartPad troubleshooting page.
A basic Dart program
The following code uses many of Dart’s most basic features:
1. // Define a function.
2. printInteger(int aNumber) {
3. print('The number is $aNumber.'); // Print to console.
4. }
6. // This is where the app starts executing.
7. main() {
8. var number = 42; // Declare and initialize a variable.
9. printInteger(number); // Call a function.
10. }
Here’s what this program uses that applies to all (or almost all) Dart apps:
// *This is a comment.*
A single-line comment. Dart also supports multi-line and document comments. For details, see Comments.
int
A type. Some of the other built-in types are String, List, and bool.
42
A number literal. Number literals are a kind of compile-time constant.
print()
A handy way to display output.
'...' (or "...")
A string literal.
$*variableName* (or ${*expression*})
String interpolation: including a variable or expression’s string equivalent inside of a string literal. For more information, see Strings.
main()
The special, required, top-level function where app execution starts. For more information, see The main() function.
var
A way to declare a variable without specifying its type.
Note: This site’s code follows the conventions in the Dart style guide.
Important concepts
As you learn about the Dart language, keep these facts and concepts in mind:
- Everything you can place in a variable is an object, and every object is an instance of a class. Even numbers, functions, and
nullare objects. All objects inherit from the Object class. - Although Dart is strongly typed, type annotations are optional because Dart can infer types. In the code above,
numberis inferred to be of typeint. When you want to explicitly say that no type is expected, use the special typedynamic. - Dart supports generic types, like
List<int>(a list of integers) orList<dynamic>(a list of objects of any type). - Dart supports top-level functions (such as
main()), as well as functions tied to a class or object (static and instance methods, respectively). You can also create functions within functions (nested or local functions). - Similarly, Dart supports top-level variables, as well as variables tied to a class or object (static and instance variables). Instance variables are sometimes known as fields or properties.
- Unlike Java, Dart doesn’t have the keywords
public,protected, andprivate. If an identifier starts with an underscore (_), it’s private to its library. For details, see Libraries and visibility. - Identifiers can start with a letter or underscore (_), followed by any combination of those characters plus digits.
- Dart has both expressions (which have runtime values) and statements (which don’t). For example, the conditional expression
condition ? expr1 : expr2has a value ofexpr1orexpr2. Compare that to an if-else statement, which has no value. A statement often contains one or more expressions, but an expression can’t directly contain a statement. - Dart tools can report two kinds of problems: warnings and errors. Warnings are just indications that your code might not work, but they don’t prevent your program from executing. Errors can be either compile-time or run-time. A compile-time error prevents the code from executing at all; a run-time error results in an exception being raised while the code executes.
Keywords
The following table lists the words that the Dart language treats specially.
| abstract 2 | else | import 2 | super |
| as 2 | enum | in | switch |
| assert | export 2 | interface 2 | sync 1 |
| async 1 | extends | is | this |
| await 3 | extension 2 | library 2 | throw |
| break | external 2 | mixin 2 | true |
| case | factory 2 | new | try |
| catch | false | null | typedef 2 |
| class | final | on 1 | var |
| const | finally | operator 2 | void |
| continue | for | part 2 | while |
| covariant 2 | Function 2 | rethrow | with |
| default | get 2 | return | yield 3 |
| deferred 2 | hide 1 | set 2 | |
| do | if | show 1 | |
| dynamic 2 | implements 2 | static 2 |
Avoid using these words as identifiers. However, if necessary, the keywords marked with superscripts can be identifiers:
- Words with the superscript 1 are contextual keywords, which have meaning only in specific places. They’re valid identifiers everywhere.
- Words with the superscript 2 are built-in identifiers. To simplify the task of porting JavaScript code to Dart, these keywords are valid identifiers in most places, but they can’t be used as class or type names, or as import prefixes.
- Words with the superscript 3 are newer, limited reserved words related to the asynchrony support that was added after Dart’s 1.0 release. You can’t use
awaitoryieldas an identifier in any function body marked withasync,async*, orsync*.
All other words in the table are reserved words, which can’t be identifiers.
Variables
Here’s an example of creating a variable and initializing it:
1. var name = 'Bob';
Variables store references. The variable called name contains a reference to a String object with a value of “Bob”.
The type of the name variable is inferred to be String, but you can change that type by specifying it. If an object isn’t restricted to a single type, specify the Object or dynamic type, following design guidelines.
1. dynamic name = 'Bob';
Another option is to explicitly declare the type that would be inferred:
1. String name = 'Bob';
Note: This page follows the style guide recommendation of using var, rather than type annotations, for local variables.
Default value
Uninitialized variables have an initial value of null. Even variables with numeric types are initially null, because numbers—like everything else in Dart—are objects.
1. int lineCount;
2. assert(lineCount == null);
Note: Production code ignores the assert() call. During development, on the other hand, assert(*condition*) throws an exception if condition is false. For details, see Assert.
Final and const
If you never intend to change a variable, use final or const, either instead of var or in addition to a type. A final variable can be set only once; a const variable is a compile-time constant. (Const variables are implicitly final.) A final top-level or class variable is initialized the first time it’s used.
Note: Instance variables can be final but not const. Final instance variables must be initialized before the constructor body starts — at the variable declaration, by a constructor parameter, or in the constructor’s initializer list.
Here’s an example of creating and setting a final variable:
1. final name = 'Bob'; // Without a type annotation
2. final String nickname = 'Bobby';
You can’t change the value of a final variable:
1. name = 'Alice'; // Error: a final variable can only be set once.
Use const for variables that you want to be compile-time constants. If the const variable is at the class level, mark it static const. Where you declare the variable, set the value to a compile-time constant such as a number or string literal, a const variable, or the result of an arithmetic operation on constant numbers:
1. const bar = 1000000; // Unit of pressure (dynes/cm2)
2. const double atm = 1.01325 * bar; // Standard atmosphere
The const keyword isn’t just for declaring constant variables. You can also use it to create constant values, as well as to declare constructors that create constant values. Any variable can have a constant value.
1. var foo = const [];
2. final bar = const [];
3. const baz = []; // Equivalent to `const []`
You can omit const from the initializing expression of a const declaration, like for baz above. For details, see DON’T use const redundantly.
You can change the value of a non-final, non-const variable, even if it used to have a const value:
1. foo = [1, 2, 3]; // Was const []
You can’t change the value of a const variable:
1. baz = [42]; // Error: Constant variables can't be assigned a value.
As of Dart 2.5, you can define constants that use type checks and casts (is and as), collection if, and spread operators (... and ...?):
1. // Valid compile-time constants as of Dart 2.5.
2. const Object i = 3; // Where i is a const Object with an int value...
3. const list = [i as int]; // Use a typecast.
4. const map = {if (i is int) i: "int"}; // Use is and collection if.
5. const set = {if (list is List<int>) ...list}; // ...and a spread.
For more information on using const to create constant values, see Lists, Maps, and Classes.
Built-in types
The Dart language has special support for the following types:
- numbers
- strings
- booleans
- lists (also known as arrays)
- sets
- maps
- runes (for expressing Unicode characters in a string)
- symbols
You can initialize an object of any of these special types using a literal. For example, 'this is a string' is a string literal, and true is a boolean literal.
Because every variable in Dart refers to an object—an instance of a class—you can usually use constructors to initialize variables. Some of the built-in types have their own constructors. For example, you can use the Map() constructor to create a map.
Numbers
Dart numbers come in two flavors:
Integer values no larger than 64 bits, depending on the platform. On the Dart VM, values can be from -263 to 263 - 1. Dart that’s compiled to JavaScript uses JavaScript numbers, allowing values from -253 to 253 - 1.
64-bit (double-precision) floating-point numbers, as specified by the IEEE 754 standard.
Both int and double are subtypes of num. The num type includes basic operators such as +, -, /, and *, and is also where you’ll find abs(), ceil(), and floor(), among other methods. (Bitwise operators, such as >>, are defined in the int class.) If num and its subtypes don’t have what you’re looking for, the dart:math library might.
Integers are numbers without a decimal point. Here are some examples of defining integer literals:
1. var x = 1;
2. var hex = 0xDEADBEEF;
If a number includes a decimal, it is a double. Here are some examples of defining double literals:
1. var y = 1.1;
2. var exponents = 1.42e5;
As of Dart 2.1, integer literals are automatically converted to doubles when necessary:
1. double z = 1; // Equivalent to double z = 1.0.
Version note: Before Dart 2.1, it was an error to use an integer literal in a double context.
Here’s how you turn a string into a number, or vice versa:
1. // String -> int
2. var one = int.parse('1');
3. assert(one == 1);
5. // String -> double
6. var onePointOne = double.parse('1.1');
7. assert(onePointOne == 1.1);
9. // int -> String
10. String oneAsString = 1.toString();
11. assert(oneAsString == '1');
13. // double -> String
14. String piAsString = 3.14159.toStringAsFixed(2);
15. assert(piAsString == '3.14');
The int type specifies the traditional bitwise shift (<<, >>), AND (&), and OR (|) operators. For example:
1. assert((3 << 1) == 6); // 0011 << 1 == 0110
2. assert((3 >> 1) == 1); // 0011 >> 1 == 0001
3. assert((3 | 4) == 7); // 0011 | 0100 == 0111
Literal numbers are compile-time constants. Many arithmetic expressions are also compile-time constants, as long as their operands are compile-time constants that evaluate to numbers.
1. const msPerSecond = 1000;
2. const secondsUntilRetry = 5;
3. const msUntilRetry = secondsUntilRetry * msPerSecond;
Strings
A Dart string is a sequence of UTF-16 code units. You can use either single or double quotes to create a string:
1. var s1 = 'Single quotes work well for string literals.';
2. var s2 = "Double quotes work just as well.";
3. var s3 = 'It\'s easy to escape the string delimiter.';
4. var s4 = "It's even easier to use the other delimiter.";
You can put the value of an expression inside a string by using ${expression}. If the expression is an identifier, you can skip the {}. To get the string corresponding to an object, Dart calls the object’s toString() method.
1. var s = 'string interpolation';
3. assert('Dart has $s, which is very handy.' ==
4. 'Dart has string interpolation, ' +
5. 'which is very handy.');
6. assert('That deserves all caps. ' +
7. '${s.toUpperCase()} is very handy!' ==
8. 'That deserves all caps. ' +
9. 'STRING INTERPOLATION is very handy!');
Note: The == operator tests whether two objects are equivalent. Two strings are equivalent if they contain the same sequence of code units.
You can concatenate strings using adjacent string literals or the + operator:
1. var s1 = 'String '
2. 'concatenation'
3. " works even over line breaks.";
4. assert(s1 ==
5. 'String concatenation works even over '
6. 'line breaks.');
8. var s2 = 'The + operator ' + 'works, as well.';
9. assert(s2 == 'The + operator works, as well.');
Another way to create a multi-line string: use a triple quote with either single or double quotation marks:
1. var s1 = '''
2. You can create
3. multi-line strings like this one.
4. ''';
6. var s2 = """This is also a
7. multi-line string.""";
You can create a “raw” string by prefixing it with r:
1. var s = r'In a raw string, not even \n gets special treatment.';
See Runes and grapheme clusters for details on how to express Unicode characters in a string.
Literal strings are compile-time constants, as long as any interpolated expression is a compile-time constant that evaluates to null or a numeric, string, or boolean value.
1. // These work in a const string.
2. const aConstNum = 0;
3. const aConstBool = true;
4. const aConstString = 'a constant string';
6. // These do NOT work in a const string.
7. var aNum = 0;
8. var aBool = true;
9. var aString = 'a string';
10. const aConstList = [1, 2, 3];
12. const validConstString = '$aConstNum $aConstBool $aConstString';
13. // const invalidConstString = '$aNum $aBool $aString $aConstList';
For more information on using strings, see Strings and regular expressions.
Booleans
To represent boolean values, Dart has a type named bool. Only two objects have type bool: the boolean literals true and false, which are both compile-time constants.
Dart’s type safety means that you can’t use code like if (*nonbooleanValue*) or assert (*nonbooleanValue*). Instead, explicitly check for values, like this:
1. // Check for an empty string.
2. var fullName = '';
3. assert(fullName.isEmpty);
5. // Check for zero.
6. var hitPoints = 0;
7. assert(hitPoints <= 0);
9. // Check for null.
10. var unicorn;
11. assert(unicorn == null);
13. // Check for NaN.
14. var iMeantToDoThis = 0 / 0;
15. assert(iMeantToDoThis.isNaN);
Lists
Perhaps the most common collection in nearly every programming language is the array, or ordered group of objects. In Dart, arrays are List objects, so most people just call them lists.
Dart list literals look like JavaScript array literals. Here’s a simple Dart list:
1. var list = [1, 2, 3];
Note: Dart infers that list has type List<int>. If you try to add non-integer objects to this list, the analyzer or runtime raises an error. For more information, read about type inference.
Lists use zero-based indexing, where 0 is the index of the first element and list.length - 1 is the index of the last element. You can get a list’s length and refer to list elements just as you would in JavaScript:
1. var list = [1, 2, 3];
2. assert(list.length == 3);
3. assert(list[1] == 2);
5. list[1] = 1;
6. assert(list[1] == 1);
To create a list that’s a compile-time constant, add const before the list literal:
1. var constantList = const [1, 2, 3];
2. // constantList[1] = 1; // Uncommenting this causes an error.
Dart 2.3 introduced the spread operator (...) and the null-aware spread operator (...?), which provide a concise way to insert multiple elements into a collection.
For example, you can use the spread operator (...) to insert all the elements of a list into another list:
1. var list = [1, 2, 3];
2. var list2 = [0, ...list];
3. assert(list2.length == 4);
If the expression to the right of the spread operator might be null, you can avoid exceptions by using a null-aware spread operator (...?):
1. var list;
2. var list2 = [0, ...?list];
3. assert(list2.length == 1);
For more details and examples of using the spread operator, see the spread operator proposal.
Dart 2.3 also introduced collection if and collection for, which you can use to build collections using conditionals (if) and repetition (for).
Here’s an example of using collection if to create a list with three or four items in it:
1. var nav = [
2. 'Home',
3. 'Furniture',
4. 'Plants',
5. if (promoActive) 'Outlet'
6. ];
Here’s an example of using collection for to manipulate the items of a list before adding them to another list:
1. var listOfInts = [1, 2, 3];
2. var listOfStrings = [
3. '#0',
4. for (var i in listOfInts) '#$i'
5. ];
6. assert(listOfStrings[1] == '#1');
For more details and examples of using collection if and for, see the control flow collections proposal.
The List type has many handy methods for manipulating lists. For more information about lists, see Generics and Collections.
Sets
A set in Dart is an unordered collection of unique items. Dart support for sets is provided by set literals and the Set type.
Version note: Although the Set type has always been a core part of Dart, set literals were introduced in Dart 2.2.
Here is a simple Dart set, created using a set literal:
1. var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
Note: Dart infers that halogens has the type Set<String>. If you try to add the wrong type of value to the set, the analyzer or runtime raises an error. For more information, read about type inference.
To create an empty set, use {} preceded by a type argument, or assign {} to a variable of type Set:
1. var names = <String>{};
2. // Set<String> names = {}; // This works, too.
3. // var names = {}; // Creates a map, not a set.
Set or map? The syntax for map literals is similar to that for set literals. Because map literals came first, {} defaults to the Map type. If you forget the type annotation on {} or the variable it’s assigned to, then Dart creates an object of type Map<dynamic, dynamic>.
Add items to an existing set using the add() or addAll() methods:
1. var elements = <String>{};
2. elements.add('fluorine');
3. elements.addAll(halogens);
Use .length to get the number of items in the set:
1. var elements = <String>{};
2. elements.add('fluorine');
3. elements.addAll(halogens);
4. assert(elements.length == 5);
To create a set that’s a compile-time constant, add const before the set literal:
1. final constantSet = const {
2. 'fluorine',
3. 'chlorine',
4. 'bromine',
5. 'iodine',
6. 'astatine',
7. };
8. // constantSet.add('helium'); // Uncommenting this causes an error.
As of Dart 2.3, sets support spread operators (... and ...?) and collection ifs and fors, just like lists do. For more information, see the list spread operator and list collection operator discussions.
For more information about sets, see Generics and Sets.
Maps
In general, a map is an object that associates keys and values. Both keys and values can be any type of object. Each key occurs only once, but you can use the same value multiple times. Dart support for maps is provided by map literals and the Map type.
Here are a couple of simple Dart maps, created using map literals:
1. var gifts = {
2. // Key: Value
3. 'first': 'partridge',
4. 'second': 'turtledoves',
5. 'fifth': 'golden rings'
6. };
8. var nobleGases = {
9. 2: 'helium',
10. 10: 'neon',
11. 18: 'argon',
12. };
Note: Dart infers that gifts has the type Map<String, String> and nobleGases has the type Map<int, String>. If you try to add the wrong type of value to either map, the analyzer or runtime raises an error. For more information, read about type inference.
You can create the same objects using a Map constructor:
1. var gifts = Map();
2. gifts['first'] = 'partridge';
3. gifts['second'] = 'turtledoves';
4. gifts['fifth'] = 'golden rings';
6. var nobleGases = Map();
7. nobleGases[2] = 'helium';
8. nobleGases[10] = 'neon';
9. nobleGases[18] = 'argon';
Note: You might expect to see new Map() instead of just Map(). As of Dart 2, the new keyword is optional. For details, see Using constructors.
Add a new key-value pair to an existing map just as you would in JavaScript:
1. var gifts = {'first': 'partridge'};
2. gifts['fourth'] = 'calling birds'; // Add a key-value pair
Retrieve a value from a map the same way you would in JavaScript:
1. var gifts = {'first': 'partridge'};
2. assert(gifts['first'] == 'partridge');
If you look for a key that isn’t in a map, you get a null in return:
1. var gifts = {'first': 'partridge'};
2. assert(gifts['fifth'] == null);
Use .length to get the number of key-value pairs in the map:
1. var gifts = {'first': 'partridge'};
2. gifts['fourth'] = 'calling birds';
3. assert(gifts.length == 2);
To create a map that’s a compile-time constant, add const before the map literal:
1. final constantMap = const {
2. 2: 'helium',
3. 10: 'neon',
4. 18: 'argon',
5. };
7. // constantMap[2] = 'Helium'; // Uncommenting this causes an error.
As of Dart 2.3, maps support spread operators (... and ...?) and collection if and for, just like lists do. For details and examples, see the spread operator proposal and the control flow collections proposal.
For more information about maps, see Generics and Maps.
Runes and grapheme clusters
In Dart, runes expose the Unicode code points of a string. As of Dart 2.6, use the characters package to view or manipulate user-perceived characters, also known as Unicode (extended) grapheme clusters.
Unicode defines a unique numeric value for each letter, digit, and symbol used in all of the world’s writing systems. Because a Dart string is a sequence of UTF-16 code units, expressing Unicode code points within a string requires special syntax. The usual way to express a Unicode code point is \uXXXX, where XXXX is a 4-digit hexadecimal value. For example, the heart character (♥) is \u2665. To specify more or less than 4 hex digits, place the value in curly brackets. For example, the laughing emoji (😆) is \u{1f606}.
If you need to read or write individual Unicode characters, use the characters getter defined on String by the characters package. The returned Characters object is the string as a sequence of grapheme clusters. Here’s an example of using the characters API:
1. import 'package:characters/characters.dart';
2. ...
3. var hi = 'Hi 🇩🇰';
4. print(hi);
5. print('The end of the string: ${hi.substring(hi.length - 1)}');
6. print('The last character: ${hi.characters.last}\n');
The output, depending on your environment, looks something like this:
1. $ dart bin/main.dart
2. Hi 🇩🇰
3. The end of the string: ???
4. The last character: 🇩🇰
For details on using the characters package to manipulate strings, see the example and API reference for the characters package.
Symbols
A Symbol object represents an operator or identifier declared in a Dart program. You might never need to use symbols, but they’re invaluable for APIs that refer to identifiers by name, because minification changes identifier names but not identifier symbols.
To get the symbol for an identifier, use a symbol literal, which is just # followed by the identifier:
1. #radix
2. #bar
Symbol literals are compile-time constants.
Functions
Dart is a true object-oriented language, so even functions are objects and have a type, Function. This means that functions can be assigned to variables or passed as arguments to other functions. You can also call an instance of a Dart class as if it were a function. For details, see Callable classes.
Here’s an example of implementing a function:
1. bool isNoble(int atomicNumber) {
2. return _nobleGases[atomicNumber] != null;
3. }
Although Effective Dart recommends type annotations for public APIs, the function still works if you omit the types:
1. isNoble(atomicNumber) {
2. return _nobleGases[atomicNumber] != null;
3. }
For functions that contain just one expression, you can use a shorthand syntax:
1. bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
The => *expr* syntax is a shorthand for { return *expr*; }. The => notation is sometimes referred to as arrow syntax.
Note: Only an expression—not a statement—can appear between the arrow (=>) and the semicolon (;). For example, you can’t put an if statement there, but you can use a conditional expression.
A function can have two types of parameters: required and optional. The required parameters are listed first, followed by any optional parameters. Optional parameters can be named or positional.
Note: Some APIs — notably Flutter widget constructors — use only named parameters, even for parameters that are mandatory. See the next section for details.
Optional parameters
Optional parameters can be either named or positional, but not both.
Named parameters
When calling a function, you can specify named parameters using *paramName*: *value*. For example:
1. enableFlags(bold: true, hidden: false);
When defining a function, use {*param1*, *param2*, …} to specify named parameters:
1. /// Sets the [bold] and [hidden] flags ...
2. void enableFlags({bool bold, bool hidden}) {...}
Although named parameters are a kind of optional parameter, you can annotate them with @required to indicate that the parameter is mandatory — that users must provide a value for the parameter. For example:
1. const Scrollbar({Key key, @required Widget child})
If someone tries to create a Scrollbar without specifying the child argument, then the analyzer reports an issue.
To use the @required annotation, depend on the meta package and import package:meta/meta.dart.
Positional parameters
Wrapping a set of function parameters in [] marks them as optional positional parameters:
1. String say(String from, String msg, [String device]) {
2. var result = '$from says $msg';
3. if (device != null) {
4. result = '$result with a $device';
5. }
6. return result;
7. }
Here’s an example of calling this function without the optional parameter:
1. assert(say('Bob', 'Howdy') == 'Bob says Howdy');
And here’s an example of calling this function with the third parameter:
1. assert(say('Bob', 'Howdy', 'smoke signal') ==
2. 'Bob says Howdy with a smoke signal');
Default parameter values
Your function can use = to define default values for both named and positional parameters. The default values must be compile-time constants. If no default value is provided, the default value is null.
Here’s an example of setting default values for named parameters:
1. /// Sets the [bold] and [hidden] flags ...
2. void enableFlags({bool bold = false, bool hidden = false}) {...}
4. // bold will be true; hidden will be false.
5. enableFlags(bold: true);
Deprecation note: Old code might use a colon (:) instead of = to set default values of named parameters. The reason is that originally, only : was supported for named parameters. That support might be deprecated, so we recommend that you use = to specify default values.
The next example shows how to set default values for positional parameters:
1. String say(String from, String msg,
2. [String device = 'carrier pigeon', String mood]) {
3. var result = '$from says $msg';
4. if (device != null) {
5. result = '$result with a $device';
6. }
7. if (mood != null) {
8. result = '$result (in a $mood mood)';
9. }
10. return result;
11. }
13. assert(say('Bob', 'Howdy') ==
14. 'Bob says Howdy with a carrier pigeon');
You can also pass lists or maps as default values. The following example defines a function, doStuff(), that specifies a default list for the list parameter and a default map for the gifts parameter.
1. void doStuff(
2. {List<int> list = const [1, 2, 3],
3. Map<String, String> gifts = const {
4. 'first': 'paper',
5. 'second': 'cotton',
6. 'third': 'leather'
7. }}) {
8. print('list: $list');
9. print('gifts: $gifts');
10. }
The main() function
Every app must have a top-level main() function, which serves as the entrypoint to the app. The main() function returns void and has an optional List<String> parameter for arguments.
Here’s an example of the main() function for a web app:
1. void main() {
2. querySelector('#sample_text_id')
3. ..text = 'Click me!'
4. ..onClick.listen(reverseText);
5. }
Note: The .. syntax in the preceding code is called a cascade. With cascades, you can perform multiple operations on the members of a single object.
Here’s an example of the main() function for a command-line app that takes arguments:
1. // Run the app like this: dart args.dart 1 test
2. void main(List<String> arguments) {
3. print(arguments);
5. assert(arguments.length == 2);
6. assert(int.parse(arguments[0]) == 1);
7. assert(arguments[1] == 'test');
8. }
You can use the args library to define and parse command-line arguments.
Functions as first-class objects
You can pass a function as a parameter to another function. For example:
1. void printElement(int element) {
2. print(element);
3. }
5. var list = [1, 2, 3];
7. // Pass printElement as a parameter.
8. list.forEach(printElement);
You can also assign a function to a variable, such as:
1. var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!';
2. assert(loudify('hello') == '!!! HELLO !!!');
This example uses an anonymous function. More about those in the next section.
Anonymous functions
Most functions are named, such as main() or printElement(). You can also create a nameless function called an anonymous function, or sometimes a lambda or closure. You might assign an anonymous function to a variable so that, for example, you can add or remove it from a collection.
An anonymous function looks similar to a named function— zero or more parameters, separated by commas and optional type annotations, between parentheses.
The code block that follows contains the function’s body:
([[*Type*] *param1*[, …]]) {
*codeBlock*;
};
The following example defines an anonymous function with an untyped parameter, item. The function, invoked for each item in the list, prints a string that includes the value at the specified index.
1. var list = ['apples', 'bananas', 'oranges'];
2. list.forEach((item) {
3. print('${list.indexOf(item)}: $item');
4. });
Click Run to execute the code.
If the function contains only one statement, you can shorten it using arrow notation. Paste the following line into DartPad and click Run to verify that it is functionally equivalent.
1. list.forEach(
2. (item) => print('${list.indexOf(item)}: $item'));
Lexical scope
Dart is a lexically scoped language, which means that the scope of variables is determined statically, simply by the layout of the code. You can “follow the curly braces outwards” to see if a variable is in scope.
Here is an example of nested functions with variables at each scope level:
1. bool topLevel = true;
3. void main() {
4. var insideMain = true;
6. void myFunction() {
7. var insideFunction = true;
9. void nestedFunction() {
10. var insideNestedFunction = true;
12. assert(topLevel);
13. assert(insideMain);
14. assert(insideFunction);
15. assert(insideNestedFunction);
16. }
17. }
18. }
Notice how nestedFunction() can use variables from every level, all the way up to the top level.
Lexical closures
A closure is a function object that has access to variables in its lexical scope, even when the function is used outside of its original scope.
Functions can close over variables defined in surrounding scopes. In the following example, makeAdder() captures the variable addBy. Wherever the returned function goes, it remembers addBy.
1. /// Returns a function that adds [addBy] to the
2. /// function's argument.
3. Function makeAdder(num addBy) {
4. return (num i) => addBy + i;
5. }
7. void main() {
8. // Create a function that adds 2.
9. var add2 = makeAdder(2);
11. // Create a function that adds 4.
12. var add4 = makeAdder(4);
14. assert(add2(3) == 5);
15. assert(add4(3) == 7);
16. }
Testing functions for equality
Here’s an example of testing top-level functions, static methods, and instance methods for equality:
1. void foo() {} // A top-level function
3. class A {
4. static void bar() {} // A static method
5. void baz() {} // An instance method
6. }
8. void main() {
9. var x;
11. // Comparing top-level functions.
12. x = foo;
13. assert(foo == x);
15. // Comparing static methods.
16. x = A.bar;
17. assert(A.bar == x);
19. // Comparing instance methods.
20. var v = A(); // Instance #1 of A
21. var w = A(); // Instance #2 of A
22. var y = w;
23. x = w.baz;
25. // These closures refer to the same instance (#2),
26. // so they're equal.
27. assert(y.baz == x);
29. // These closures refer to different instances,
30. // so they're unequal.
31. assert(v.baz != w.baz);
32. }
Return values
All functions return a value. If no return value is specified, the statement return null; is implicitly appended to the function body.
1. foo() {}
3. assert(foo() == null);
Operators
Dart defines the operators shown in the following table. You can override many of these operators, as described in Overridable operators.
| Description | Operator |
|---|---|
| unary postfix | expr++ expr— () [] . ?. |
| unary prefix | -expr !expr ~expr ++expr —expr await expr |
| multiplicative | / % ~/ |
| additive | + - |
| shift | << >> >>> |
| bitwise AND | & |
| bitwise XOR | ^ |
| bitwise OR | | |
| relational and type test | >= > <= < as is is! |
| equality | == != |
| logical AND | && |
| logical OR | || |
| if null | ?? |
| conditional | expr1 ? expr2 : expr3 |
| cascade | .. |
| assignment | = = /= += -= &= ^= etc. |
Warning: Operator precedence is an approximation of the behavior of a Dart parser. For definitive answers, consult the grammar in the Dart language specification.
When you use operators, you create expressions. Here are some examples of operator expressions:
1. a++
2. a + b
3. a = b
4. a == b
5. c ? a : b
6. a is T
In the operator table, each operator has higher precedence than the operators in the rows that follow it. For example, the multiplicative operator % has higher precedence than (and thus executes before) the equality operator ==, which has higher precedence than the logical AND operator &&. That precedence means that the following two lines of code execute the same way:
1. // Parentheses improve readability.
2. if ((n % i == 0) && (d % i == 0)) ...
4. // Harder to read, but equivalent.
5. if (n % i == 0 && d % i == 0) ...
Warning: For operators that work on two operands, the leftmost operand determines which version of the operator is used. For example, if you have a Vector object and a Point object, aVector + aPoint uses the Vector version of +.
Arithmetic operators
Dart supports the usual arithmetic operators, as shown in the following table.
| Operator | Meaning |
|---|---|
+ |
Add |
– |
Subtract |
-expr |
Unary minus, also known as negation (reverse the sign of the expression) |
* |
Multiply |
/ |
Divide |
~/ |
Divide, returning an integer result |
% |
Get the remainder of an integer division (modulo) |
Example:
1. assert(2 + 3 == 5);
2. assert(2 - 3 == -1);
3. assert(2 * 3 == 6);
4. assert(5 / 2 == 2.5); // Result is a double
5. assert(5 ~/ 2 == 2); // Result is an int
6. assert(5 % 2 == 1); // Remainder
8. assert('5/2 = ${5 ~/ 2} r ${5 % 2}' == '5/2 = 2 r 1');
Dart also supports both prefix and postfix increment and decrement operators.
| Operator | Meaning |
|---|---|
++var |
var = var + 1 (expression value is var + 1) |
var++ |
var = var + 1 (expression value is var) |
—var |
var = var – 1 (expression value is var – 1) |
var— |
var = var – 1 (expression value is var) |
Example:
1. var a, b;
3. a = 0;
4. b = ++a; // Increment a before b gets its value.
5. assert(a == b); // 1 == 1
7. a = 0;
8. b = a++; // Increment a AFTER b gets its value.
9. assert(a != b); // 1 != 0
11. a = 0;
12. b = --a; // Decrement a before b gets its value.
13. assert(a == b); // -1 == -1
15. a = 0;
16. b = a--; // Decrement a AFTER b gets its value.
17. assert(a != b); // -1 != 0
Equality and relational operators
The following table lists the meanings of equality and relational operators.
| Operator | Meaning |
|---|---|
== |
Equal; see discussion below |
!= |
Not equal |
> |
Greater than |
< |
Less than |
>= |
Greater than or equal to |
<= |
Less than or equal to |
To test whether two objects x and y represent the same thing, use the == operator. (In the rare case where you need to know whether two objects are the exact same object, use the identical() function instead.) Here’s how the == operator works:
- If x or y is null, return true if both are null, and false if only one is null.
- Return the result of the method invocation
*x*.==(*y*). (That’s right, operators such as==are methods that are invoked on their first operand. You can even override many operators, including==, as you’ll see in Overridable operators.)
Here’s an example of using each of the equality and relational operators:
1. assert(2 == 2);
2. assert(2 != 3);
3. assert(3 > 2);
4. assert(2 < 3);
5. assert(3 >= 3);
6. assert(2 <= 3);
Type test operators
The as, is, and is! operators are handy for checking types at runtime.
| Operator | Meaning |
|---|---|
as |
Typecast (also used to specify library prefixes) |
is |
True if the object has the specified type |
is! |
False if the object has the specified type |
The result of obj is T is true if obj implements the interface specified by T. For example, obj is Object is always true.
Use the as operator to cast
(本文超出站点单文档体积上限,已截断)
