Dart Syntax and Null Safety

Master Dart's syntax patterns for writing clean, idiomatic code.

Collections

Dart
// List (ordered,允许重复)
var fruits = ['apple', 'banana', 'cherry'];
fruits.add('date');
fruits.addAll(['elderberry', 'fig']);
fruits.removeAt(0);           // Remove by index
fruits.remove('banana');      // Remove by value

// List operations
fruits.map((f) => f.toUpperCase()).toList();     // Transform
fruits.where((f) => f.startsWith('b')).toList(); // Filter
fruits.any((f) => f.length > 5);                 // Has any?
fruits.every((f) => f.length > 2);               // All match?
fruits.fold(0, (sum, f) => sum + f.length);      // Reduce
fruits.expand((f) => f.split('')).toList();      // Flatten

// Spread operator
var all = [...fruits, 'grape', ...['honeydew', 'kiwi']];

// Conditional collection element
var list = [
  'item1',
  if (includeItem2) 'item2',
  for (var i = 0; i < 3; i++) 'repeated_$i',
];

// Map (key-value pairs)
var scores = {
  'Alice': 95,
  'Bob': 87,
  'Charlie': 92,
};

scores['Alice']           // 95
scores['Dave'] = 88;      // Add
scores.remove('Bob');     // Remove
scores.containsKey('Alice');  // true
scores.values.toList();       // [95, 92, 88]
scores.entries.map((e) => '${e.key}: ${e.value}').join(', ');

// Set (unique elements)
var colors = {'red', 'green', 'blue'};
colors.add('red');         // Already exists, no change
colors.length;             // 3

colors.union({'yellow'});          // {'red','green','blue','yellow'}
colors.intersection({'red','blue'}); // {'red','blue'}

Control Flow

Dart
// if/else
if (score >= 90) {
  grade = 'A';
} else if (score >= 80) {
  grade = 'B';
} else {
  grade = 'C';
}

// Ternary
String msg = isLoggedIn ? 'Welcome back' : 'Please log in';

// switch
var command = 'open';
switch (command) {
  case 'open':
    print('Opening...');
    break;
  case 'close':
    print('Closing...');
    break;
  default:
    print('Unknown command');
}

// Enhanced switch (Dart 3)
String describe(String command) => switch (command) {
  'open'  => 'Opening...',
  'close' => 'Closing...',
  _       => 'Unknown command',
};

// Pattern matching
var data = {'name': 'Alice', 'age': 28};
if (data case {'name': String name, 'age': int age}) {
  print('$name is $age years old');
}

// for and for-in
for (var i = 0; i < 10; i++) {
  print(i);
}

for (var fruit in fruits) {
  print(fruit);
}

// for-each
fruits.forEach((f) => print(f));

Classes

Dart
class Person {
  final String name;
  final int age;
  String? email;
  
  // Constructor
  Person({required this.name, required this.age, this.email});
  
  // Named constructors
  Person.anonymous() : name = 'Anonymous', age = 0;
  Person.fromJson(Map<String, dynamic> json)
      : name = json['name'],
        age = json['age'];
  
  // Method
  bool get isAdult => age >= 18;
  
  void greet() {
    print('Hello, I\'m $name!');
  }
  
  @override
  String toString() => 'Person($name, $age)';
  
  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is Person && name == other.name && age == other.age;
  
  @override
  int get hashCode => Object.hash(name, age);
}

// Inheritance
class Student extends Person {
  final String school;
  final double gpa;
  
  Student({
    required String name,
    required int age,
    required this.school,
    required this.gpa,
  }) : super(name: name, age: age);
  
  @override
  String toString() => 'Student($name, $school, GPA: $gpa)';
}

Enums

Dart
enum Color { red, green, blue }

// Enhanced enums (with properties)
enum HttpStatus {
  ok(200, 'OK'),
  notFound(404, 'Not Found'),
  serverError(500, 'Server Error');
  
  final int code;
  final String message;
  
  const HttpStatus(this.code, this.message);
  
  bool get isSuccess => code >= 200 && code < 300;
}

HttpStatus.ok.code;       // 200
HttpStatus.ok.isSuccess;  // true

Exceptions

Dart
// Try-catch
try {
  var result = int.parse('not a number');
} on FormatException catch (e) {
  print('Parse error: ${e.message}');
} catch (e) {
  print('Unexpected: $e');
} finally {
  print('Always runs');
}

// Custom exceptions
class InsufficientFundsException implements Exception {
  final double amount;
  InsufficientFundsException(this.amount);
  
  @override
  String toString() => 'Insufficient funds: need \$$amount more';
}

💡 Tip: Use named parameters with required for clarity. Prefer final over var when the value doesn't change. Use late only when initialization can't happen in the constructor.

Next: Classes and OOP