Classes
class Person {
String name;
int birthYear;
// Constructor
Person(this.name, this.birthYear);
// Named constructor
Person.born(this.name) : birthYear = DateTime.now().year;
// Getter
int get age => DateTime.now().year - birthYear;
// Method
String greet() => 'Hello, I am $name';
}
var p = Person('Ada', 1985);
print(p.age); // 41
print(p.greet()); // Hello, I am Ada
Initializer list
class Point {
final double x;
final double y;
Point(double x, double y)
: x = x.abs(),
y = y.abs();
}
Redirecting constructors
class Person {
String name;
int birthYear;
Person(this.name, this.birthYear);
Person.unnamed(int birthYear) : this('Unknown', birthYear);
}
Factory constructors
class Logger {
final String name;
static final Map<String, Logger> _cache = {};
Logger._internal(this.name);
factory Logger(String name) {
return _cache.putIfAbsent(name, () => Logger._internal(name));
}
}
Const constructors
class ImmutablePoint {
final double x;
final double y;
const ImmutablePoint(this.x, this.y);
}
var origin = const ImmutablePoint(0, 0);
Inheritance
Dart uses extends for single inheritance:
class Animal {
String name;
Animal(this.name);
void speak() => print('$name makes a sound');
}
class Dog extends Animal {
String breed;
Dog(String name, this.breed) : super(name);
@override
void speak() => print('$name barks!');
}
Abstract classes
abstract class Shape {
double area();
void describe() {
print('Area: ${area()}');
}
}
class Circle extends Shape {
final double radius;
Circle(this.radius);
@override
double area() => 3.14159 * radius * radius;
}
Interfaces
Every class implicitly defines an interface. Use implements to create a class with the same API but different implementation:
class MockPerson implements Person {
@override
String get name => 'Mock';
@override
int get birthYear => 2000;
@override
String greet() => 'Mock greeting';
}
Mixins
Mixins share code between classes without inheritance:
mixin Logging {
void log(String message) => print('[LOG] $message');
}
mixin Timestamp {
String get timestamp => DateTime.now().toIso8601String();
}
class Service with Logging, Timestamp {
void run() {
log('Service started at $timestamp');
}
}
Mixin with constraint
mixin Wag on Animal {
void wag() => print('$name wags tail!');
}
class GoodDog extends Dog with Wag {
GoodDog(String name, String breed) : super(name, breed);
}
Extensions
Add methods to existing types without modifying them:
extension StringX on String {
bool get isEmail => contains('@') && contains('.');
String capitalized => isEmpty ? this : '${this[0].toUpperCase()}${substring(1)}';
}
'hello'.capitalized; // 'Hello'
'[email protected]'.isEmail; // true
Enums
enum Status { pending, active, done }
var s = Status.active;
s.name; // 'active'
s.index; // 1
Status.values; // [Status.pending, Status.active, Status.done]
// Enhanced enums (Dart 2.17+)
enum Vehicle {
car(tires: 4, speed: 120),
bicycle(tires: 2, speed: 25),
motorcycle(tires: 2, speed: 180);
final int tires;
final int speed;
const Vehicle({required this.tires, required this.speed});
String get description => '$name has $tires tires, top speed $speed mph';
}
Next: Async