[Dart Language Tour] Variables, Built-in types, Comments
Variables, Built-in types, Comments
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 | // type annotations |
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; |
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 |
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) |
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 []; |
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. |
You can define constants that use type checks and casts (is
and as
), collection if
, and spread operators (...
and ...?
):
1 | const Object i = 3; // Where i is a const Object with an int value... |
Note: Although a final
object cannot be modified, its fields can be changed. In comparison, a const object and its fields cannot be changed: they’re immutable.
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:
int
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 - https://stackoverflow.com/questions/2802957/number-of-bits-in-javascript-numbers/2803010#2803010, allowing values from -253 to 253 - 1.
double
64-bit (double-precision) floating-point numbers, as specified by the IEEE 754 standard.
Both in
t 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
- https://api.dart.dev/stable/dart-math library might.
Integers are numbers without a decimal point. Here are some examples of defining integer literals:
1 | var x = 1; |
If a number includes a decimal, it is a double. Here are some examples of defining double literals:
1 | var y = 1.1; |
Here’s how you turn a string into a number, or vice versa:
1 | // String -> int |
The int type specifies the traditional bitwise shift (<<
, >>
), AND (&
), and OR (|
) operators. For example:
1 | assert((3 << 1) == 6); // 0011 << 1 == 0110 |
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; |
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.'; |
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'; |
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 ' |
Another way to create a multi-line string: use a triple quote with either single or double quotation marks:
1 | var s1 = ''' |
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 - https://dart.dev/guides/language/language-tour#characters 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. |
For more information on using strings, see Strings and regular expressions - https://dart.dev/guides/libraries/library-tour#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. |
Lists
Perhaps the most common collection in nearly every programming language is the array, or ordered group of objects. In Dart, arrays are List
- https://api.dart.dev/stable/dart-core/List-class.html 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 - https://dart.dev/guides/language/type-system#type-inference.
You can add a comma after the last item in a Dart collection literal. This trailing comma doesn’t affect the collection, but it can help prevent copy-paste errors.
1 | var list = [ |
Lists use zero-based indexing, where 0 is the index of the first value and list.length - 1 is the index of the last value. You can get a list’s length and refer to list values just as you would in JavaScript:
1 | var list = [1, 2, 3]; |
To create a list that’s a compile-time constant, add const before the list literal:
1 | var constantList = const [1, 2, 3]; |
Dart 2.3 introduced the spread operator (...
) and the null-aware spread operator (...?
), which provide a concise way to insert multiple values into a collection.
For example, you can use the spread operator (...
) to insert all the values of a list into another list:
1 | var list = [1, 2, 3]; |
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; |
For more details and examples of using the spread operator, see the spread operator proposal - https://github.com/dart-lang/language/blob/master/accepted/2.3/spread-collections/feature-specification.md.
Dart also offers 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 = [ |
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]; |
For more details and examples of using collection if
and for
, see the control flow collections proposal - https://github.com/dart-lang/language/blob/master/accepted/2.3/control-flow-collections/feature-specification.md.
The List type has many handy methods for manipulating lists. For more information about lists, see Generics - https://dart.dev/guides/language/language-tour#generics and Collections - https://dart.dev/guides/libraries/library-tour#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
- https://api.dart.dev/stable/dart-core/Set-class.html type.
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
To create an empty set, use {}
preceded by a type argument, or assign {}
to a variable of type Set:
1 | var names = <String>{}; |
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>{}; |
To create a set that’s a compile-time constant, add const before the set literal:
1 | final constantSet = const { |
Sets support spread operators (...
and ...?
) and collection ifs and fors, just like lists do. For more information, see the list spread operator - https://dart.dev/guides/language/language-tour#spread-operator and list collection operator discussions.
For more information about sets, see Generics - https://dart.dev/guides/language/language-tour#generics and Sets - https://dart.dev/guides/libraries/library-tour#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 = { |
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(); |
Note: If you come from a language like C# or Java, you might expect to see new Map() instead of just Map()
. In Dart, the new keyword is optional. For details, see Using constructors - https://dart.dev/guides/language/language-tour#using-constructors.
Add a new key-value pair to an existing map just as you would in JavaScript:
1 | var gifts = {'first': 'partridge'}; |
Maps support spread operators (...
and ...?
) and collection if and for, just like lists do. For details and examples, see the spread operator proposal - https://github.com/dart-lang/language/blob/master/accepted/2.3/spread-collections/feature-specification.md and the control flow collections proposal - https://github.com/dart-lang/language/blob/master/accepted/2.3/control-flow-collections/feature-specification.md.
For more information about maps, see Generics - https://dart.dev/guides/language/language-tour#generics and Maps - https://dart.dev/guides/libraries/library-tour#maps.
Runes and grapheme clusters
In Dart, runes expose the Unicode code points of a string. You can 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'; |
The output, depending on your environment, looks something like this:
1 | dart bin/main.dart |
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 |
Symbol literals are compile-time constants.
Comments
Dart supports single-line comments, multi-line comments, and documentation comments.
Single-line comments
A single-line comment begins with //
. Everything between //
and the end of line is ignored by the Dart compiler.
1 | void main() { |
Multi-line comments
A multi-line comment begins with /*
and ends with */
. Everything between /*
and */
is ignored by the Dart compiler (unless the comment is a documentation comment; see the next section). Multi-line comments can nest.
1 | void main() { |
Documentation comments
Documentation comments are multi-line or single-line comments that begin with ///
or /**
. Using ///
on consecutive lines has the same effect as a multi-line doc comment.
Inside a documentation comment, the Dart compiler ignores all text unless it is enclosed in brackets. Using brackets, you can refer to classes, methods, fields, top-level variables, functions, and parameters. The names in brackets are resolved in the lexical scope of the documented program element.
Here is an example of documentation comments with references to other classes and arguments:
1 | /// A domesticated South American camelid (Lama glama). |
In the generated documentation, [Food] becomes a link to the API docs for the Food class.
To parse Dart code and generate HTML documentation, you can use the SDK’s documentation generation tool - https://github.com/dart-lang/dartdoc#dartdoc. For an example of generated documentation, see the Dart API documentation - https://api.dart.dev/stable. For advice on how to structure your comments, see Guidelines for Dart Doc Comments - https://dart.dev/guides/language/effective-dart/documentation.
References
[1] Language tour | Dart - https://dart.dev/guides/language/language-tour
[2] Effective Dart: Design | Dart - https://dart.dev/guides/language/effective-dart/design