Dart
Values & Types
Dart has type inference: it can detect and interpret type if not specified
Numbers
int i = 1;
double dbl = 1.0;
num nbr = 1; // works for int and double
String
String h = "hello";
print("$h world"); // "hello world"
String multiline = """Hello
world""";
Null
Dart don’t like null values. Try to specify if you allow variables to be null ?
or if you guarantee they can’t be !
.
var a; // return null if nothing is precised
var foo = bar!; // bar is guaranteed to be never null
int? age = null; // age can be an int or be null
// Assign a value if is null
a ??= "value";
var b = a ?? "value";
Enum
enum Drink { coffee, tea, soft }
Drink espresso = Drink.coffee;
Variables
Assign
dynamic d = 1; // can change type & value
var v = 1; // can't change type, can change the value
final f = 1; // can't change type nor value (but can reassign)
const c = 1; // can't change type nor value (immutable)
Constants
final
final list = [1,2,3];
list.add(4); // [1,2,3,4]
Use it if the value is not known at compile time (database/api requests, runtime computed values like new DateTime.now()
, etc.).
final name = "Alice";
name = "Bob"; // Error: a final variable can only be set once.
When object are final
, you can modify items inside objects
const
Use it when the value of the variable is known before runtime.
const date = new DateTime.now();
// Error: New expression is not a constant expression
You can use it to declare constant values. The value is immutable, not the variable
var list = const [1,2,3];
list.add(4); // Error: Unsupported operation
list = [1,2,3,4]; // [1,2,3,4];
final list = const [1,2,3];
list.add(4); // Error: Unsupported operation
list = [1,2,3,4]; // Error: Can't assign to the final variable 'list'
If you’re using const
inside a class, you have to use static
class Person {
static const name = "Alice";
}
Unlike final
, const
is immutable: items inside objects can’t be changed
late
In some cases, like top-level variables and instance variable, Dart can’t determine if non-null value is set to a variable before it’s used. You can use late
.
late int number;
void main() {
number = 42;
print(number); // 42
}
It’s also used to lazily initializing a variable
late String name = getName();
Functions
void logHi() { print("hi"); }; // simple function without return
String sayHi() { return "hi"; }; // specify return type
num addOne(nbr) { return 1 + nbr }; // with parameter
num addTwo(nbr) => 2 + nbr; // arrow function (shorthand)
Parameters
String sayFullname(String firstname, String lastname) {
return "$firstname $lastname";
}
sayFullname("John", "Doe"); // John Doe
Optional parameters
You can make a parameter optional
String sayFullname(String firstname, [String? lastname]) {
if (lastname == null) return firstname;
return "$firstname $lastname";
}
sayFullname("Alice", "Cooper"); // John Doe
Default value
You can specify a default value with optional parameters
String sayName([String name = "John"]) => name;
sayName(); // John
Named parameters
Use named argument to help structures your data. They can be placed in any order.
String assignNumber({
String firstname = "John",
String? lastname
}) {
return "Hi, I'm $firstname $lastname";
};
assignNumber(lastname: "Doe"); // Hi, I'm John Doe
assignNumber(); // Hello, my name is John null
Required
You can make named parameters mandatory with required
.
num addOne({required int number}) { return 1 + $number; };
addOne(); // Error: Required named parameter 'number' must be provided.
Operators
Cascades
querySelector('#confirm')
..text = 'Confirm’
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'));
Lists & Sets
Lists are basically the same as array in other language. Sets are unordered collection of unique items. Almost all methods apply for both concept.
List<int> list = [1,2,3]; // list of int
list.length; // 3
list[1]; // 2
list = [...list, 4]; // [1,2,3,4]
Set<int> set = {1,2,3}; // set of int
Add stuff
// Spread operator
var list = [1,2,3];
list = [...list, 4]; // [1,2,3,4]
// Appends items at the end of the list
final list = [1,2];
list.add(3); // [1,2,3]
list.addAll([4,5]); // [1,2,3,4,5]
// Insert at specific index
final list = [1,5];
list.insert(1,2); // [1,2,5]
list.insertAll(2,[3,4]); // [1,2,3,4,5]
Maps
var map = {
"one": 1,
"two": 2
}
print(map["one"]); // 1
Classes
class Person {
final String name; // instance variable
final String _greet = "Hi"; // private variable
Person(this.name); // constructor
String greets() => "$_greet, my name is ${this.name}"; // method
}
var client = Person("John");
print(client.name); // John
print(client.greets()); // Hi, my name is John
Properties
Instance variables are class properties. They create implicit getter and setter methods, if they’re not final
.
class Person {
int? age;
final String name;
Person(this.name);
}
var client = Person("Alice");
var clientName = client.name; // getter for 'name'
client.age = 42; // setter for 'age'
Instance variables can be final
, but you have to use static
with const
static
Variables (and methods) can be static: they don’t need to create an instance of the class to be used. It means it can’t use this
.
class Person {
static const name = "Alice";
static String greets() => "Hi!";
}
print(Person.name); // Alice
print(Person.greets()); // Hi!
Methods
Getter & setter
Getter & setter methods are created along with properties.
Constructors
You can create a constructor by writing a method with the same name as the class
class Person {
final String firstname;
final String lastname;
Person(this.firstname, this.lastname); // constructor
}
You can expends the initializer to do some operations before instance is created
class Person {
final String firstname;
final String lastname;
final String fullname;
Person(this.firstname, this.lastname) {
// …
}
}
class Person {
final String firstname;
final String lastname;
final String fullname;
Person(String firstname, String lastname) :
firstname = firstname,
lastname = lastname,
fullname = "$firstname $lastname";
}
Callable class
class Math { call(a,b) => a+b; }
var cal = Math();
print(cal(1,2)); // 3
Implementation
// ABSTRACT: Interface (can't be instantiated)
abstract class Animal { void makeSound(); }
// IMPLMENTS
class Dog implements Animal {
@override // annotate element overriding
String makeSound() => "wuf";
}
// MIXIN: reuse variables and methods
mixin Tamed {
String? name;
String pet() => "You pet $name";
}
// EXTENDS class with mixins
class Pug extends Dog with Tamed {
Pug(name){this.name = name;}
}
void main() {
var dog = Pug("Cookie");
print(dog.makeSound()); // wuf (from Dog class)
print(dog.pet()); // You pet Cookie (from Tamed mixin)
}
Errors handling
// BOOLEAN
assert(2 < 1); // False: error raised (Assertion failed)
// TRY CATCH
try {
someFunction();
} on SpecificException catch (err) {
print("Specific error: $err");
} catch (err) {
print('Unkown error: $err');
} finally {
backupFunction();
}
Good to know
- In Dart, everything that is placed in a variable is an object
Packages & Modules
import 'package:flutter/material.dart'; // import package
import dart:core; // import built-in library
import '../path/lib.dart'; // import custom library
import 'lib' show foo; // import only foo
import 'lib' hide bar; // import all but bar
Packages
dart pub add # add package (add line to pubspec.yaml)
dart pub get # get packages according to pubspec.yaml
Libraries
Built-in library
A tour of the core libraries – Dart website
Custom library
- External library → lib from external packages
- Local library → lib defined inside the entrypoint package
Resources
- github.com/dart-lang/sdk – Github repo
- dart.dev – Official website
- pub.dev – Package repo
- devdocs.io/dart~2 – Devdoc page
- dartpad.dev – Online editor