Skip to content

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:

dart
var name = 'Alice';        // String
var age = 25;              // int
var height = 5.8;          // double
var isStudent = true;      // bool

Once assigned, the type is fixed:

dart
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:

dart
String name = 'Bob';
int age = 30;
double price = 19.99;
bool isActive = false;

Dynamic Type

Use dynamic when the type can change:

dart
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:

dart
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:

dart
const double pi = 3.14159;
const int maxUsers = 100;

// const now = DateTime.now();  // Error: Must be compile-time constant

Difference Between final and const

dart
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):

dart
int score = 95;
int hexValue = 0xFF;
int negativeNum = -42;

double

64-bit floating-point numbers:

dart
double temperature = 36.6;
double price = 99.99;
double scientific = 1.42e5;  // 142000.0

num

Parent type of both int and double:

dart
num value1 = 10;      // int
num value2 = 10.5;    // double

2. Strings

Strings represent sequences of characters:

dart
String greeting = 'Hello';
String message = "Welcome";
String multiline = '''
This is a
multi-line
string
''';

3. Booleans

Boolean values are true or false:

dart
bool isLoggedIn = true;
bool hasPermission = false;

4. Lists (Arrays)

Ordered collections of objects:

dart
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:

dart
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:

dart
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:

dart
var heart = '\u2665';  // ♥
var smiley = '\u{1F600}';  // 😀

Runes input = Runes('\u2665 \u{1F600}');
print(String.fromCharCodes(input));  // ♥ 😀

8. Symbols

Identifiers used in reflection:

dart
Symbol sym = #mySymbol;

Type Checking and Casting

Type Checking with is

dart
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

dart
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:

dart
int? count;
print(count);  // null

String? name;
print(name);  // null

Late Variables

Use late for variables that will be initialized later:

dart
late String description;

void initialize() {
  description = 'Initialized later';
}

void main() {
  initialize();
  print(description);  // OK
}

Type Inference

Dart can infer types from context:

dart
var numbers = [1, 2, 3];  // List<int>
var map = {'key': 'value'};  // Map<String, String>

// Generic type inference
var list = <String>[];  // List<String>

Best Practices

  1. Prefer var or explicit types over dynamic
  2. Use final for variables that won't change
  3. Use const for compile-time constants
  4. Be explicit with types in public APIs
  5. Use type inference for local variables when the type is obvious

Examples

Complete Example

dart
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:

Content is for learning and research only.