Variables
Understand how to declare and use variables in Dart.
What is it?
Variables are named storage locations in memory that hold values. In Dart, variables can store various types of data including numbers, strings, booleans, lists, maps, and custom objects.
Why does it exist?
Variables exist to:
- Store and manipulate data in programs
- Reference values by meaningful names
- Enable dynamic behavior in applications
- Track state throughout program execution
- Pass data between functions and classes
Variable Declaration
Explicit Typing
// Declare with explicit type
String name = 'Alice';
int age = 25;
double height = 1.75;
bool isActive = true;
List<String> hobbies = ['reading', 'swimming'];
Map<String, int> scores = {'math': 95, 'science': 90};
Type Inference with var
// Dart infers the type
var name = 'Alice'; // String
var age = 25; // int
var height = 1.75; // double
var isActive = true; // bool
var hobbies = ['reading', 'swimming']; // List<String>
var scores = {'math': 95, 'science': 90}; // Map<String, int>
Type Inference with final
// Runtime constants (assigned once)
final name = 'Alice';
final age = 25;
final currentTime = DateTime.now(); // Set at runtime
// Cannot reassign
// name = 'Bob'; // Error!
Compile-time Constants with const
// Compile-time constants
const pi = 3.14159;
const appName = 'MyApp';
const maxRetries = 3;
// Must be known at compile time
const currentTime = DateTime.now(); // Error! Not compile-time constant
Null Safety
Non-nullable Variables
// By default, variables cannot be null
String name = 'Alice'; // Must have a value
int age = 25; // Must have a value
Nullable Variables
// Use '?' to allow null values
String? maybeName = null;
int? maybeAge = null;
// Can be assigned later
String? nickname;
nickname = 'Ally';
Late Initialization
// Declare without initial value
late String description;
late int userId;
// Initialize later
void initializeUser() {
description = 'Administrator';
userId = 42;
}
// Access after initialization
void printUser() {
print('$description: $userId');
}
Variable Types
Numbers
// int - Whole numbers
int count = 10;
int negative = -5;
int hex = 0xFF; // Hexadecimal
int binary = 0b1010; // Binary
// double - Floating point numbers
double price = 19.99;
double decimal = 3.14159;
double scientific = 1.5e12;
// num - Can be either int or double
num number = 42;
number = 3.14; // Can change type
Strings
// Single quotes
String single = 'Hello';
// Double quotes
String double = "World";
// String interpolation
String greeting = 'Hello, $name';
String message = '${name.toUpperCase()} says hello';
// Multi-line strings
String multiline = '''
This is a
multi-line
string
''';
// Raw strings (ignore escape sequences)
String raw = r'C:\Users\name\file.txt';
Booleans
// Only true or false
bool isActive = true;
bool isComplete = false;
// Cannot be null by default
bool? maybeFlag = null; // Nullable boolean
Lists
// Generic list with type
List<String> names = ['Alice', 'Bob', 'Charlie'];
// Type inference
var names = ['Alice', 'Bob', 'Charlie'];
// Empty list
List<int> empty = [];
var empty = <String>[];
// Fixed-length list
var fixed = List<int>.filled(3, 0);
fixed[0] = 1;
// fixed.add(4); // Error! Cannot add to fixed-length list
// List operations
names.add('David');
names.insert(1, 'Eve');
names.remove('Bob');
names.removeAt(0);
Sets
// Generic set with type
Set<String> uniqueNames = {'Alice', 'Bob', 'Charlie'};
// Type inference
var uniqueNames = {'Alice', 'Bob', 'Charlie'};
// Empty set (not a map!)
Set<int> empty = {};
var empty = <int>{};
// Set operations
uniqueNames.add('David');
uniqueNames.add('Bob'); // Won't add duplicate
uniqueNames.remove('Alice');
Maps
// Generic map with types
Map<String, int> scores = {
'Alice': 95,
'Bob': 87,
'Charlie': 92,
};
// Type inference
var scores = {
'Alice': 95,
'Bob': 87,
'Charlie': 92,
};
// Empty map
Map<String, int> empty = {};
var empty = <String, int>{};
// Map operations
scores['David'] = 88;
scores.remove('Bob');
var aliceScore = scores['Alice']; // 95
Advanced Variable Concepts
Getters and Setters
class Person {
String _name;
Person(this._name);
// Getter
String get name => _name;
// Setter with validation
set name(String value) {
if (value.isNotEmpty) {
_name = value;
}
}
}
Variables in Classes
class User {
// Instance variables
String name;
int age;
final String id; // Must be initialized in constructor
late String email; // Late initialized
// Static variables (class level)
static int totalUsers = 0;
// Constants (compile-time)
static const int maxAge = 150;
User(this.name, this.age, this.id) {
totalUsers++;
}
// Instance method
void display() {
print('$name, $age years old');
}
}
Scope
class Example {
// Class scope
var classVariable = 'class';
void method() {
// Method scope
var methodVariable = 'method';
if (true) {
// Block scope
var blockVariable = 'block';
print(classVariable); // Accessible
print(methodVariable); // Accessible
}
// print(blockVariable); // Error! Not accessible outside block
}
}
Type Conversion
Explicit Casting
// Number conversions
int toDouble = 42;
double doubleValue = toDouble.toDouble();
double toInt = 42.7;
int intValue = toInt.toInt(); // 42 (truncates)
// String conversions
String numberString = '123';
int parsedInt = int.parse(numberString);
double parsedDouble = double.parse('3.14');
// To string
String intString = 42.toString();
String doubleString = 3.14159.toStringAsFixed(2); // '3.14'
Common Operators
Assignment
// Basic assignment
var x = 5;
// Compound assignment
x += 3; // x = x + 3
x -= 2; // x = x - 2
x *= 2; // x = x * 2
x /= 2; // x = x / 2
x %= 3; // x = x % 3
Increment/Decrement
var count = 0;
// Prefix (increment before use)
print(++count); // 1
// Postfix (increment after use)
print(count++); // 1
print(count); // 2
Null-aware Operators
String? maybeName = null;
// Null-aware access
String? upperName = maybeName?.toUpperCase(); // null
// Null-aware assignment
maybeName ??= 'Guest'; // Assign if null
// Null coalescing
String displayName = maybeName ?? 'Anonymous';
Best Practices
Naming Conventions
// Use camelCase for variables
String firstName = 'Alice';
int userAge = 25;
// Use UPPER_SNAKE_CASE for constants
const MAX_RETRIES = 3;
const DEFAULT_NAME = 'Guest';
// Use _ prefix for private variables
String _internalState = 'private';
Variable Usage Guidelines
// Prefer final for variables that don't change
final name = 'Alice';
final age = 25;
// Use var when type is obvious from initialization
var items = ['a', 'b', 'c']; // Type is clear
// Explicitly type when type isn't obvious
Map<String, dynamic> response = fetchData();
// Avoid dynamic unless absolutely necessary
dynamic value = 'hello'; // Prefer specific types
Common Mistakes
Null Safety Violation
Wrong:
String name; // Non-nullable variable not initialized
print(name); // Error!
Correct:
String name = 'Alice';
print(name);
// Or
String? name;
print(name); // Prints null (but handle it)
Type Mismatch
Wrong:
int count = '5'; // Error! Can't assign String to int
Correct:
int count = int.parse('5');
Reassigning Final Variables
Wrong:
final name = 'Alice';
name = 'Bob'; // Error! Can't reassign final
Correct:
var name = 'Alice';
name = 'Bob'; // Works
Summary
Variables are fundamental to programming in Dart. Understanding how to declare, initialize, and use variables effectively is essential for writing clear, efficient, and safe code.
Next Steps
Now that you understand variables, continue to:
Did You Know?
- Dart's type inference is very smart and can infer complex types
- The Dart VM optimizes variables based on their usage patterns
- Dart's null safety helps prevent billions of dollars in bugs
- The language supports both strong and weak typing through inference
- Dart variables are references to objects, not primitive values