Variables and Types
Variables in Dart
Variables are containers for storing data values. Dart is a statically typed language with type inference, meaning you can declare variables with or without explicit types.
Variable Declaration
Using var
The var keyword lets Dart infer the type:
var name = 'Alice'; // String
var age = 25; // int
var height = 5.8; // double
var isStudent = true; // bool
Once assigned, the type is fixed:
var count = 10;
// count = 'ten'; // Error: A value of type 'String' can't be assigned to a variable of type 'int'
Explicit Type Declaration
You can explicitly specify the type:
String name = 'Bob';
int age = 30;
double price = 19.99;
bool isActive = false;
Dynamic Type
Use dynamic when the type can change:
dynamic value = 42;
value = 'Now a string'; // OK
value = true; // OK
⚠️ Warning: Avoid dynamic when possible, as it bypasses type safety.
Final and Const
final
A final variable can be set only once:
final String city = 'New York';
// city = 'Boston'; // Error: Can't assign to final variable
final currentTime = DateTime.now(); // Set at runtime
const
A const variable is a compile-time constant:
const double pi = 3.14159;
const int maxUsers = 100;
// const now = DateTime.now(); // Error: Must be compile-time constant
Difference Between final and const
final list1 = [1, 2, 3];
const list2 = [1, 2, 3];
list1.add(4); // OK: The list itself can be modified
// list2.add(4); // Error: Cannot modify const list
// final is set at runtime
final time1 = DateTime.now();
// const must be known at compile time
const time2 = DateTime.now(); // Error!
Built-in Types
1. Numbers
int
Integer values (64-bit, -2^63 to 2^63-1):
int score = 95;
int hexValue = 0xFF;
int negativeNum = -42;
double
64-bit floating-point numbers:
double temperature = 36.6;
double price = 99.99;
double scientific = 1.42e5; // 142000.0
num
Parent type of both int and double:
num value1 = 10; // int
num value2 = 10.5; // double
2. Strings
Strings represent sequences of characters:
String greeting = 'Hello';
String message = "Welcome";
String multiline = '''
This is a
multi-line
string
''';
3. Booleans
Boolean values are true or false:
bool isLoggedIn = true;
bool hasPermission = false;
4. Lists (Arrays)
Ordered collections of objects:
List<int> numbers = [1, 2, 3, 4, 5];
var fruits = ['apple', 'banana', 'orange'];
// Access elements
print(fruits[0]); // apple
// Modify
fruits.add('grape');
fruits[1] = 'mango';
5. Sets
Unordered collections of unique items:
Set<String> colors = {'red', 'green', 'blue'};
var numbers = {1, 2, 3, 3, 4}; // {1, 2, 3, 4} - duplicates removed
colors.add('yellow');
colors.remove('red');
6. Maps
Key-value pairs:
Map<String, int> ages = {
'Alice': 25,
'Bob': 30,
'Charlie': 35,
};
// Access values
print(ages['Alice']); // 25
// Add/modify
ages['David'] = 28;
ages['Alice'] = 26;
7. Runes
Unicode code points of a string:
var heart = '\u2665'; // ♥
var smiley = '\u{1F600}'; // 😀
Runes input = Runes('\u2665 \u{1F600}');
print(String.fromCharCodes(input)); // ♥ 😀
8. Symbols
Identifiers used in reflection:
Type Checking and Casting
Type Checking with is
var value = 42;
if (value is int) {
print('It\'s an integer');
}
if (value is! String) {
print('It\'s not a string');
}
Type Casting with as
dynamic obj = 'Hello';
String str = obj as String; // Cast to String
// Safe casting
if (obj is String) {
String str = obj; // No cast needed, type promotion
}
Default Values
Uninitialized variables have a default value of null:
int? count;
print(count); // null
String? name;
print(name); // null
Late Variables
Use late for variables that will be initialized later:
late String description;
void initialize() {
description = 'Initialized later';
}
void main() {
initialize();
print(description); // OK
}
Type Inference
Dart can infer types from context:
var numbers = [1, 2, 3]; // List<int>
var map = {'key': 'value'}; // Map<String, String>
// Generic type inference
var list = <String>[]; // List<String>
Best Practices
- Prefer
var or explicit types over dynamic
- Use
final for variables that won't change
- Use
const for compile-time constants
- Be explicit with types in public APIs
- Use type inference for local variables when the type is obvious
Examples
Complete Example
void main() {
// Basic types
var name = 'Alice';
int age = 25;
double height = 5.8;
bool isStudent = true;
// Collections
List<String> hobbies = ['reading', 'coding', 'gaming'];
Map<String, dynamic> person = {
'name': name,
'age': age,
'hobbies': hobbies,
};
// Constants
const double pi = 3.14159;
final currentDate = DateTime.now();
// Print information
print('Name: $name');
print('Age: $age');
print('Height: $height meters');
print('Is student: $isStudent');
print('Hobbies: ${hobbies.join(', ')}');
print('Person: $person');
print('Pi: $pi');
print('Date: $currentDate');
}
Next Steps
Now that you understand variables and types, let's explore: