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, allowing values from -253 to 253 - 1.
double
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.)
Integers are numbers without a decimal point. Here are some examples of defining integer literals:
var y = 1.1;
var exponents = 1.42e5;
If a number includes a decimal, it is a double
. Here are some examples of defining double
literals:
var y = 1.1;var y = 1.1;
var exponents = 1.42e5;
var exponents = 1.42e5;
As of Dart 2.1, integer literals are automatically converted to doubles when necessary:
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:
// String -> int
var one = int.parse('1');
assert(one == 1);
// String -> double
var onePointOne = double.parse('1.1');
assert(onePointOne == 1.1);
// int -> String
String oneAsString = 1.toString();
assert(oneAsString == '1');
// double -> String
String piAsString = 3.14159.toStringAsFixed(2);
assert(piAsString == '3.14');
The int
type specifies the traditional bitwise shift (<<
, >>
), AND (&
), and OR (|
) operators. For example:
assert((3 << 1) == 6); // 0011 << 1 == 0110
assert((3 >> 1) == 1); // 0011 >> 1 == 0001
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.
const msPerSecond = 1000;
const secondsUntilRetry = 5;
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:
var s1 = 'Single quotes work well for string literals.';
var s2 = "Double quotes work just as well.";
var s3 = 'It\'s easy to escape the string delimiter.';
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.
var s = 'string interpolation';
assert('Dart has $s, which is very handy.' == 'Dart has string interpolation, ' + 'which is very handy.');
assert('That deserves all caps. ' + '${s.toUpperCase()} is very handy!' == 'That deserves all caps. ' + '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:
var s1 = 'String ' 'concatenation' " works even over line breaks.";
assert(s1 == 'String concatenation works even over ' 'line breaks.');
var s2 = 'The + operator ' + 'works, as well.';
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:
var s1 = ''' You can create multi-line strings like this one. ''';
var s2 = """This is also a multi-line string.""";
You can create a “raw” string by prefixing it with r
:
var s = r'In a raw string, not even \n gets special treatment
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.
// These work in a const string. const aConstNum = 0;
const aConstBool = true;
const aConstString = 'a constant string';
// These do NOT work in a const string.
var aNum = 0;
var aBool = true;
var aString = 'a string';
const aConstList = [1, 2, 3];
const validConstString = '$aConstNum $aConstBool $aConstString';
// const invalidConstString = '$aNum $aBool $aString $aConstList';
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:
// Check for an empty string.
var fullName = '';
assert(fullName.isEmpty);
// Check for zero.
var hitPoints = 0;
assert(hitPoints <= 0);
// Check for null.
var unicorn;
assert(unicorn == null);
// Check for NaN.
var iMeantToDoThis = 0 / 0;
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:
var list = [1, 2, 3];
Note: Dart infers that
list
has typeList<int>
. If you try to add non-integer objects to this list, the analyzer or runtime raises an error.
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:
var list = [1, 2, 3];
assert(list.length == 3);
assert(list[1] == 2);
list[1] = 1;
assert(list[1] == 1);
To create a list that’s a compile-time constant, add const before the list literal:
var constantList = const [1, 2, 3];
// 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:
var list = [1, 2, 3];
var list2 = [0, ...list];
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 (...?
):
var list;
var list2 = [0, ...?list];
assert(list2.length == 1);
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:
var nav = [ 'Home', 'Furniture', 'Plants', if (promoActive) 'Outlet' ];
Here’s an example of using collection for to manipulate the items of a list before adding them to another list:
var listOfInts = [1, 2, 3];
var listOfStrings = [ '#0', for (var i in listOfInts) '#$i' ];
assert(listOfStrings[1] == '#1');
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:
var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
Note: Dart infers that
halogens
has the typeSet<String>
. If you try to add the wrong type of value to the set, the analyzer or runtime raises an error.
To create an empty set, use {} preceded by a type argument, or assign {} to a variable of type Set:
var names = <String>{};
// Set<String> names = {}; // This works, too.
// 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 theMap
type. If you forget the type annotation on {}
or the variable it’s assigned to, then Dart creates an object of typeMap<dynamic, dynamic>
.
Add items to an existing set using the add()
or addAll()
methods:
var elements = <String>{};
elements.add('fluorine');
elements.addAll(halogens);
Use .length
to get the number of items in the set:
var elements = <String>{};
elements.add('fluorine');
elements.addAll(halogens);
assert(elements.length == 5);
To create a set that’s a compile-time constant, add const before the set literal:
final constantSet = const { 'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine', };
// 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.
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.
var gifts = { 'first': 'partridge', 'second': 'turtledoves', 'fifth': 'golden rings' };
var nobleGases = { 2: 'helium', 10: 'neon', 18: 'argon', };
Note: Dart infers that gifts has the type
Map<String, String>
andnobleGases
has the typeMap<int, String>
. If you try to add the wrong type of value to either map, the analyzer or runtime raises an error.
You can create the same objects using a Map
constructor:
var gifts = Map();
gifts['first'] = 'partridge';
gifts['second'] = 'turtledoves';
gifts['fifth'] = 'golden rings';
var nobleGases = Map();
nobleGases[2] = 'helium';
nobleGases[10] = 'neon';
nobleGases[18] = 'argon';
Note: You might expect to see
new Map()
instead of justMap()
. As of Dart 2, thenew
keyword is optional.
Add a new key-value pair to an existing map just as you would in JavaScript:
var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds'; // Add a key-value pair
Retrieve a value from a map the same way you would in JavaScript:
var gifts = {'first': 'partridge'};
assert(gifts['first'] == 'partridge');
If you look for a key that isn’t in a map, you get a null
in return:
var gifts = {'first': 'partridge'};
assert(gifts['fifth'] == null);
Use .length
to get the number of key-value pairs in the map:
var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds';
assert(gifts.length == 2);
To create a map that’s a compile-time constant, add const before the map literal:
final constantMap = const { 2: 'helium', 10: 'neon', 18: 'argon', };
// 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.
Runes
In Dart, runes are the UTF-32 code points of a string.
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 32-bit Unicode values 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{1f600}
.
The String
class has several properties you can use to extract rune information. The codeUnitAt
and codeUnit
properties return 16-bit code units. Use the runes
property to get the runes of a string. The following example illustrates the relationship between runes, 16-bit code units, and 32-bit code points.
main() {
var clapping = '\u{1f44f}';
print(clapping); print(clapping.codeUnits);
print(clapping.runes.toList());
Runes input = new Runes( '\u2665 \u{1f605} \u{1f60e} \u{1f47b} \u{1f596} \u{1f44d}');
print(new String.fromCharCodes(input));
}
Note: Be careful when manipulating runes using list operations. This approach can easily break down, depending on the particular language, character set, and operation.
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:
#radix
#bar
Symbol literals are compile-time constants.