Operators
Operators are special symbols that perform operations on operands. Dart supports a rich set of operators for various operations.
Arithmetic Operators
dart
int a = 10, b = 3;
print(a + b); // 13 - Addition
print(a - b); // 7 - Subtraction
print(a * b); // 30 - Multiplication
print(a / b); // 3.333... - Division (returns double)
print(a ~/ b); // 3 - Integer division
print(a % b); // 1 - Modulo (remainder)
// Unary operators
print(-a); // -10 - NegationIncrement and Decrement
dart
int x = 5;
print(++x); // 6 - Pre-increment (increment then return)
print(x++); // 6 - Post-increment (return then increment)
print(x); // 7
print(--x); // 6 - Pre-decrement
print(x--); // 6 - Post-decrement
print(x); // 5Equality and Relational Operators
dart
int a = 10, b = 20;
print(a == b); // false - Equal to
print(a != b); // true - Not equal to
print(a > b); // false - Greater than
print(a < b); // true - Less than
print(a >= b); // false - Greater than or equal to
print(a <= b); // true - Less than or equal toLogical Operators
dart
bool a = true, b = false;
print(a && b); // false - AND
print(a || b); // true - OR
print(!a); // false - NOTAssignment Operators
dart
int a = 10;
a += 5; // a = a + 5 (15)
a -= 3; // a = a - 3 (12)
a *= 2; // a = a * 2 (24)
a ~/= 4; // a = a ~/ 4 (6)
a %= 4; // a = a % 4 (2)Type Test Operators
dart
var value = 'Hello';
print(value is String); // true
print(value is! int); // true
print(value is Object); // true
// Type cast
dynamic obj = 'Hello';
String str = obj as String; // Cast to StringBitwise Operators
dart
int a = 5; // 0101 in binary
int b = 3; // 0011 in binary
print(a & b); // 1 (0001) - AND
print(a | b); // 7 (0111) - OR
print(a ^ b); // 6 (0110) - XOR
print(~a); // -6 - NOT (inverts bits)
print(a << 1); // 10 (1010) - Left shift
print(a >> 1); // 2 (0010) - Right shiftConditional Expressions
Ternary Operator
dart
int age = 18;
String status = age >= 18 ? 'Adult' : 'Minor';
print(status); // AdultNull-coalescing Operator
dart
String? name;
String displayName = name ?? 'Guest';
print(displayName); // Guest
// Assign if null
name ??= 'Default';
print(name); // DefaultCascade Notation
Allows you to perform a sequence of operations on the same object:
dart
class Person {
String? name;
int? age;
void introduce() {
print('I am $name, $age years old');
}
}
void main() {
Person person = Person()
..name = 'Alice'
..age = 25
..introduce(); // I am Alice, 25 years old
// Null-aware cascade
Person? nullablePerson;
nullablePerson?..name = 'Bob'..age = 30;
}Spread Operator
dart
List<int> list1 = [1, 2, 3];
List<int> list2 = [4, 5, 6];
// Spread operator
List<int> combined = [...list1, ...list2];
print(combined); // [1, 2, 3, 4, 5, 6]
// Null-aware spread
List<int>? nullableList;
List<int> safe = [...?nullableList, 7, 8];
print(safe); // [7, 8]Null-aware Operators
Null-aware Access
dart
class Person {
String? name;
}
Person? person;
// Safe navigation
print(person?.name); // null (no error)
// Chaining
print(person?.name?.length); // nullNull-aware Assignment
dart
String? name;
name ??= 'Default'; // Assign only if null
print(name); // Default
name ??= 'Another'; // Won't assign (name is not null)
print(name); // DefaultNull Assertion
dart
String? nullable = 'Hello';
String nonNull = nullable!; // Assert non-null
print(nonNull); // Hello
// Throws error if null
String? nullValue;
// String error = nullValue!; // Error: Null check operator used on a null valueIndex Operator
dart
List<int> numbers = [10, 20, 30, 40];
print(numbers[0]); // 10
print(numbers[2]); // 30
Map<String, int> ages = {'Alice': 25, 'Bob': 30};
print(ages['Alice']); // 25Operator Precedence
From highest to lowest:
- Postfix:
expr++,expr--,(),[],.,?. - Unary prefix:
-expr,!expr,~expr,++expr,--expr - Multiplicative:
*,/,%,~/ - Additive:
+,- - Shift:
<<,>> - Bitwise AND:
& - Bitwise XOR:
^ - Bitwise OR:
| - Relational:
>=,>,<=,<,as,is,is! - Equality:
==,!= - Logical AND:
&& - Logical OR:
|| - Null-aware:
?? - Conditional:
expr1 ? expr2 : expr3 - Cascade:
..,?.. - Assignment:
=,*=,/=,+=,-=, etc.
Operator Overloading
You can override operators in custom classes:
dart
class Vector {
final double x, y;
Vector(this.x, this.y);
// Overload + operator
Vector operator +(Vector other) {
return Vector(x + other.x, y + other.y);
}
// Overload - operator
Vector operator -(Vector other) {
return Vector(x - other.x, y - other.y);
}
// Overload * operator (scalar multiplication)
Vector operator *(double scalar) {
return Vector(x * scalar, y * scalar);
}
@override
String toString() => 'Vector($x, $y)';
}
void main() {
Vector v1 = Vector(3, 4);
Vector v2 = Vector(1, 2);
print(v1 + v2); // Vector(4.0, 6.0)
print(v1 - v2); // Vector(2.0, 2.0)
print(v1 * 2); // Vector(6.0, 8.0)
}Best Practices
- Use parentheses to make complex expressions clearer
- Prefer
??over explicit null checks when providing defaults - Use cascade notation for multiple operations on the same object
- Be careful with
!- only use when you're certain the value isn't null - Use
?.for safe navigation through potentially null objects
Complete Example
dart
class Calculator {
double? lastResult;
double calculate(double a, double b, String operator) {
lastResult = switch (operator) {
'+' => a + b,
'-' => a - b,
'*' => a * b,
'/' => b != 0 ? a / b : 0,
_ => 0,
};
return lastResult!;
}
void reset() => lastResult = null;
}
void main() {
Calculator calc = Calculator()
..calculate(10, 5, '+')
..calculate(20, 4, '*');
print('Last result: ${calc.lastResult}'); // 80.0
// Null-aware operations
String? input;
String display = input ?? 'No input';
print(display); // No input
// Conditional expression
int age = 25;
String category = age >= 18 ? 'Adult' : 'Minor';
print('Category: $category'); // Adult
// Spread operator
List<int> numbers1 = [1, 2, 3];
List<int> numbers2 = [4, 5, 6];
List<int> all = [...numbers1, ...numbers2];
print('All numbers: $all'); // [1, 2, 3, 4, 5, 6]
}