Contents keyboard_arrow_down keyboard_arrow_up
- A basic Dart program
- Important concepts
- Keywords
- Variables
- Default value
- Late variables
- Final and const
- Built-in types
- Numbers
- Strings
- Booleans
- Lists
- Sets
- Maps
- Runes and grapheme clusters
- Symbols
- Functions
- Parameters
- The main[] function
- Functions as first-class objects
- Anonymous functions
- Lexical scope
- Lexical closures
- Testing functions for equality
- Return values
- Operators
- Arithmetic operators
- Equality and relational operators
- Type test operators
- Assignment operators
- Logical operators
- Bitwise and shift operators
- Conditional expressions
- Cascade notation
- Other operators
- Control flow statements
- If and else
- For loops
- While and do-while
- Break and continue
- Switch and case
- Assert
- Exceptions
- Throw
- Catch
- Finally
- Classes
- Using class members
- Using constructors
- Getting an object’s type
- Instance variables
- Constructors
- Methods
- Abstract classes
- Implicit interfaces
- Extending a class
- Extension methods
- Enumerated types
- Adding features to a class: mixins
- Class variables and methods
- Generics
- Why use generics?
- Using collection literals
- Using parameterized types with constructors
- Generic collections and the types they contain
- Restricting the parameterized type
- Using generic methods
- Libraries and visibility
- Using libraries
- Implementing libraries
- Asynchrony support
- Handling Futures
- Declaring async functions
- Handling Streams
- Generators
- Callable classes
- Isolates
- Typedefs
- Metadata
- Comments
- Single-line comments
- Multi-line comments
- Documentation comments
- Summary
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.
A basic Dart program
The following code uses many of Dart’s most basic features:
// Define a function.
void printInteger[int aNumber] {
print['The number is $aNumber.']; // Print to console.
}
// This is where the app starts executing.
void main[] {
var number = 42; // Declare and initialize a variable.
printInteger[number]; // Call a function.
}
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.void
A
special type that indicates a value that’s never used. Functions like printInteger[]
and main[]
that don’t explicitly return a value have the void
return type.int
Another type, indicating an integer. Some additional 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. The type of this variable [int
] is determined by its initial value [42
].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
null
are objects. With the exception ofnull
[if you enable sound null safety], all objects inherit from theObject
class.Although Dart is strongly typed, type annotations are optional because Dart can infer types. In the code above,
number
is inferred to be of typeint
.If you enable null safety, variables can’t contain
null
unless you say they can. You can make a variable nullable by putting a question mark [?
] at the end of its type. For example, a variable of typeint?
might be an integer, or it might benull
. If you know that an expression never evaluates tonull
but Dart disagrees, you can add!
to assert that it isn’t null [and to throw an exception if it is]. An example:int x = nullableButNotNullInt!
When you want to explicitly say that any type is allowed, use the type
Object?
[if you’ve enabled null safety],Object
, or—if you must defer type checking until runtime—the special typedynamic
.Dart supports generic types, like
List
[a list of integers] orList
[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 : expr2
has a value ofexpr1
orexpr2
. 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.
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. 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 limited reserved words related to asynchrony support. You can’t use
await
oryield
as 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:
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
type [or dynamic
if necessary].
Another option is to explicitly declare the type that would be inferred:
Default value
Uninitialized variables that have a nullable type have an initial value of
null
. [If you haven’t opted into null safety, then every variable has a nullable type.] Even variables with numeric types are initially null, because numbers—like everything else in Dart—are objects.
int? lineCount;
assert[lineCount == null];
If you enable null safety, then you must initialize the values of non-nullable variables before you use them:
You don’t have to initialize a local variable where it’s declared, but you do need to
assign it a value before it’s used. For example, the following code is valid because Dart can detect that lineCount
is non-null by the time it’s passed to print[]
:
int lineCount;
if [weLikeToCount] {
lineCount = countLines[];
} else {
lineCount = 0;
}
print[lineCount];
Top-level and class variables are lazily initialized; the initialization code runs the first time the variable is used.
Late variables
Dart 2.12 added the late
modifier, which has two use cases:
- Declaring a non-nullable variable that’s initialized after its declaration.
- Lazily initializing a variable.
Often Dart’s control flow analysis can detect when a non-nullable variable is set to a non-null value before it’s used, but sometimes analysis fails. Two common cases are top-level variables and instance variables: Dart often can’t determine whether they’re set, so it doesn’t try.
If you’re sure that a variable is set before it’s used, but Dart disagrees, you can fix the error by marking the variable as late
:
late String description;
void main[] {
description = 'Feijoada!';
print[description];
}
When you mark a variable as late
but initialize it at its declaration, then the initializer runs the first time the variable is used. This lazy initialization is handy in a couple of cases:
- The variable might not be needed, and initializing it is costly.
- You’re initializing an instance variable, and its initializer needs access to
this
.
In the following example, if the temperature
variable is never used, then the expensive readThermometer[]
function is never
called:
// This is the program's only call to readThermometer[].
late String temperature = readThermometer[]; // Lazily initialized.
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.]
Here’s an example of creating and setting a final
variable:
final name = 'Bob'; // Without a type annotation
final String nickname = 'Bobby';
You can’t change the value of a final
variable:
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:
const bar = 1000000; // Unit of pressure [dynes/cm2]
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.
var foo = const [];
final bar = const [];
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:
foo = [1, 2, 3]; // Was const []
You can’t change the value of a const
variable:
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 ...?
]:
const Object i = 3; // Where i is a const Object with an int value...
const list = [i as int]; // Use a typecast.
const map = {if [i is int] i: 'int'}; // Use is and collection if.
const set = {if [list is List] ...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:
- Numbers [
int
,double
] - Strings [
String
] -
Booleans [
bool
] - Lists [
List
, also known as arrays] - Sets [
Set
] - Maps [
Map
] -
Runes [
Runes
; often replaced by thecharacters
API] - Symbols [
Symbol
] - The value
null
[Null
]
This support includes the ability to create objects using literals. 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.
Some other types also have special roles in the Dart language:
-
Object
: The superclass of all Dart classes exceptNull
. -
Enum
: The superclass of all enums. -
Future
andStream
: Used in asynchrony support. -
Iterable
: Used in for-in loops and in synchronous generator functions. -
Never
: Indicates that an expression can never successfully finish evaluating. Most often used for functions that always throw an exception. -
dynamic
: Indicates that you want to disable static checking. Usually you should useObject
orObject?
instead. -
void
: Indicates that a value is never used. Often used as a return type.
The Object
, Object?
, Null
, and Never
classes have special roles in the class hierarchy, as described in the top-and-bottom section of
Understanding null safety.
Numbers
Dart numbers come in two flavors:
int
Integer values no larger than 64 bits, depending on the platform. On native platforms, values can be from -263 to 263 - 1. On the web, integer values are represented as JavaScript numbers [64-bit floating-point values with no fractional part] and can be 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.] 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:
var x = 1;
var hex = 0xDEADBEEF;
If a number includes a decimal, it is a double. Here are some examples of defining double literals:
var y = 1.1;
var exponents = 1.42e5;
You can also declare a variable as a num. If you do this, the variable can have both integer and double values.
num x = 1; // x can have both int and double values
x += 2.5;
Integer literals are automatically converted to doubles when necessary:
double z = 1; // Equivalent to double z = 1.0.
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 [,
>>>
], complement [~
], AND [&
], OR [|
], and XOR [^
] operators, which are useful for manipulating and masking flags in bit fields. For example:
assert[[3