Welcome to Day 2 of "Hundred Days of Flutter"! Today, we'll build on your Dart knowledge by exploring control flow, functions, and Dart's type system. These fundamentals will serve as building blocks for your Flutter journey.
Control flow structures determine the execution path of your program based on certain conditions.
void main() {
int score = 85;
if (score >= 90) {
print('Excellent!');
} else if (score >= 80) {
print('Good job!');
} else if (score >= 70) {
print('Not bad.');
} else {
print('You need to study more.');
}
}
The ternary operator is a shorthand for simple if-else statements:
String status = score >= 60 ? 'Pass' : 'Fail';
String grade = 'B';
switch (grade) {
case 'A':
print('Excellent!');
break;
case 'B':
print('Good job!');
break;
case 'C':
print('Fair.');
break;
default:
print('Invalid grade.');
}
// Standard for loop
for (int i = 0; i < 5; i++) {
print(i); // Prints 0, 1, 2, 3, 4
}
// For-in loop (for iterables)
List<String> fruits = ['apple', 'banana', 'orange'];
for (String fruit in fruits) {
print(fruit);
}
// While loop
int count = 0;
while (count < 5) {
print(count);
count++;
}
// Do-while loop (executes at least once)
int number = 0;
do {
print(number);
number++;
} while (number < 5);
break
: Exits the loop entirelycontinue
: Skips the current iteration and proceeds to the nextfor (int i = 0; i < 10; i++) {
if (i == 3) continue; // Skip 3
if (i == 8) break; // Stop at 8
print(i); // Prints 0, 1, 2, 4, 5, 6, 7
}
Functions encapsulate code that can be reused throughout your application.
// Basic function
void greet() {
print('Hello!');
}
// Function with parameters
void greetPerson(String name) {
print('Hello, $name!');
}
// Function with return value
int add(int a, int b) {
return a + b;
}
// Using the functions
void main() {
greet(); // Prints: Hello!
greetPerson('Alex'); // Prints: Hello, Alex!
int sum = add(5, 3); // sum = 8
print(sum);
}
Dart supports both optional positional and named parameters:
// Optional positional parameters (using square brackets)
String buildGreeting(String name, [String title = '']) {
if (title.isEmpty) {
return 'Hello, $name!';
}
return 'Hello, $title $name!';
}
// Optional named parameters (using curly braces)
void printUserInfo({String? name, int age = 0, String country = 'Unknown'}) {
print('Name: ${name ?? 'Anonymous'}, Age: $age, Country: $country');
}
// Using the functions
void main() {
print(buildGreeting('John')); // Hello, John!
print(buildGreeting('John', 'Dr.')); // Hello, Dr. John!
printUserInfo(name: 'Jane', age: 30); // Name: Jane, Age: 30, Country: Unknown
printUserInfo(country: 'Canada'); // Name: Anonymous, Age: 0, Country: Canada
}
For functions with a single expression, you can use the arrow syntax:
int multiply(int a, int b) => a * b;
bool isEven(int number) => number % 2 == 0;
Anonymous functions (also called lambda functions) don't have a name:
var fruits = ['apple', 'banana', 'orange'];
// Using an anonymous function with forEach
fruits.forEach((fruit) {
print('I like $fruit');
});
// Shorter version using arrow syntax
fruits.forEach((fruit) => print('I like $fruit'));
// Even shorter using shorthand syntax
fruits.forEach(print);
Dart is a statically typed language, meaning types are checked at compile-time. This helps catch errors early.
String name = 'John';
int age = 30;
// This would cause a compile-time error
// name = 50; // Error: A value of type 'int' can't be assigned to a variable of type 'String'
Dart can infer types when you use var
:
var name = 'John'; // Inferred as String
var age = 30; // Inferred as int
var height = 1.85; // Inferred as double
var isActive = true; // Inferred as bool
If you want to opt out of static typing, you can use dynamic
:
dynamic value = 'Hello';
value = 42; // Valid: dynamic can change types
value = true; // Valid: dynamic can change types
However, using dynamic
loses the benefits of static type checking.
Dart's null safety feature requires you to explicitly declare if a variable can be null:
// Non-nullable - must have a value
String name = 'John';
// Nullable - can be null
String? nullableName = null;
// Using nullable types safely
if (nullableName != null) {
print(nullableName.length); // Safe
}
// Or use the null-aware operator
print(nullableName?.length); // Safe, prints null if nullableName is null
// Null assertion operator (use with caution)
// print(nullableName!.length); // Throws exception if nullableName is null
Let's test your understanding of today's concepts:
What will be the output of the following code? ```dart var x = 10; if (x > 5) { print('A'); } else if (x > 8) { print('B'); } else { print('C'); } ```
What is the difference between `final` and `const` in Dart?
Which of the following correctly defines a function with optional named parameters in Dart?
Create a function that determines if a number is prime (only divisible by 1 and itself).
Here's a solution:
bool isPrime(int number) {
// 0 and 1 are not prime numbers
if (number <= 1) {
return false;
}
// 2 and 3 are prime numbers
if (number <= 3) {
return true;
}
// Numbers divisible by 2 or 3 are not prime
if (number % 2 == 0 || number % 3 == 0) {
return false;
}
// Check divisibility by numbers of form 6k ± 1
int i = 5;
while (i * i <= number) {
if (number % i == 0 || number % (i + 2) == 0) {
return false;
}
i += 6;
}
return true;
}
void main() {
// Test the function
List<int> numbersToCheck = [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 17, 20, 23];
for (int number in numbersToCheck) {
if (isPrime(number)) {
print('$number is a prime number');
} else {
print('$number is not a prime number');
}
}
}
?
suffixTomorrow, we'll explore Dart collections (Lists, Maps, Sets) and dive deeper into functions with higher-order functions and closures.
Begin your Flutter journey by setting up your development environment and learning the basics of Dart programming language.
Start Previous DayMaster Dart collections (Lists, Maps, Sets) and advanced function concepts like higher-order functions and closures for more powerful Flutter applications.
Start Next Day