~/icsd.ir — bash
SYSTEM_ONLINE

زبان Dart

Dart زبان رسمی Flutter است. یک زبان مدرن، شیءگرا، با type-safety قوی و null safety که توسط Google توسعه داده شده. در این فصل تمام مفاهیم Dart را که برای Flutter لازم دارید یاد می‌گیریم.

۲.۱ مقدمه

Dart زبان رسمی Flutter است. یک زبان مدرن، شیءگرا، با type-safety قوی و null safety که توسط Google توسعه داده شده. در این فصل تمام مفاهیم Dart را که برای Flutter لازم دارید یاد می‌گیریم.


هدف این فصل: تسلط بر Dart 3.x — متغیرها، توابع، کلاس‌ها، Generics، Async/Await، Null Safety، Records، Pattern Matching و Sealed Classes.

۲.۲ چرا Dart؟

وقتی Flutter ساخته می‌شد، Google می‌توانست JavaScript یا Kotlin انتخاب کند. اما Dart را برگزید، چون:

  • JIT + AOT compilation: JIT برای Hot Reload در dev، AOT برای performance بالا در production
  • Null Safety: compiler از null pointer exception جلوگیری می‌کند
  • Type Safety + Inference: سخت‌گیر اما باهوش
  • Garbage Collection: بدون نیاز به مدیریت دستی حافظه
  • Async/Await native: برای UI واکنش‌گرا
  • Single-threaded با Isolates: بدون مشکلات thread، اما با parallelism
  • Familiar syntax: اگر Java، JavaScript، C# می‌دانید، Dart آشناست

۲.۳ متغیرها


void main() {
  // 1. var - type inference
  var name = "محمدعلی";
  var age = 35;
  // name = 123; // ❌ ERROR: type already inferred to String

  // 2. صریح تایپ
  String city = "کاشان";
  int year = 1404;
  double height = 1.75;
  bool isActive = true;
  
  // 3. final - یک‌بار مقدار می‌گیرد (runtime)
  final birthYear = DateTime.now().year - age;
  // birthYear = 1990; // ❌ ERROR
  
  // 4. const - compile-time constant
  const pi = 3.14159;
  const greeting = "سلام دنیا"; // باید در زمان compile مشخص باشد
  
  // 5. dynamic - بدون type checking (مثل any در TypeScript)
  dynamic anything = 42;
  anything = "string now"; // ✅ OK اما خطرناک
  
  // 6. Object - parent همه type ها (اما type-safe)
  Object obj = "hello";
  // obj.length; // ❌ ERROR - باید cast کنید
  
  // 7. Late - مقداردهی دیرهنگام (اما non-null)
  late String description;
  description = "later";
  
  // print
  print("نام: $name، شهر: $city، سن: $age");
  // String interpolation با $ یا ${expression}
  print("سال تولد: ${DateTime.now().year - age}");
}
    

تفاوت final و const

ویژگی final const
زمان مقداردهی Runtime Compile-time
مقدار از هر چیزی (function، DateTime.now()) فقط constants
کاربرد در class فیلدهای instance فقط static
memory هر بار جدید یک نسخه (canonical)

۲.۴ Null Safety

یکی از مهم‌ترین ویژگی‌های Dart 3 — جلوگیری از null pointer exception در compile time.


void main() {
  // پیش‌فرض: متغیر non-nullable
  String name = "علی";
  // name = null; // ❌ ERROR: نمی‌توانید null بدهید
  
  // با ? متغیر nullable می‌شود
  String? nullableName;
  print(nullableName); // null - OK
  
  // اگر بخواهید method صدا بزنید
  // print(nullableName.length); // ❌ ERROR
  
  // 1. Null-aware: ?
  print(nullableName?.length); // null - OK اگر null باشد
  
  // 2. Default value: ??
  String displayName = nullableName ?? "مهمان";
  print(displayName); // مهمان
  
  // 3. ??= برای assign اگر null
  String? title;
  title ??= "بدون عنوان";
  print(title); // بدون عنوان
  
  // 4. ! - bang operator (اطمینان دارم null نیست)
  String? maybeName = "علی";
  String definitelyName = maybeName!; // اگر null باشد crash می‌کند
  
  // 5. late - بعداً مقدار می‌دهم
  late String email;
  email = "test@example.com";
  print(email); // OK
  
  // 6. Null check در شرایط
  String? input = getInput();
  if (input != null) {
    // اینجا Dart می‌داند input non-null است
    print(input.length); // ✅ OK
  }
}

String? getInput() => null;
    
توصیه: از ! (bang) فقط زمانی استفاده کنید که ۱۰۰٪ مطمئن هستید null نیست. در غیر این صورت از ?? یا if check استفاده کنید.

۲.۵ توابع (Functions)


// 1. تابع ساده
int add(int a, int b) {
  return a + b;
}

// 2. Arrow function (برای یک خط)
int multiply(int a, int b) => a * b;

// 3. Optional positional parameters
String greet(String name, [String? title]) {
  return title != null ? "$title $name" : name;
}
greet("علی");           // "علی"
greet("علی", "آقای");  // "آقای علی"

// 4. Named parameters (پرکاربرد در Flutter!)
String introduce({required String name, int age = 0, String? city}) {
  return "$name، $age ساله${city != null ? "، از $city" : ""}";
}
introduce(name: "علی");
introduce(name: "علی", age: 35, city: "کاشان");

// 5. تابع به عنوان first-class citizen
void main() {
  // Function در متغیر
  Function adder = (int a, int b) => a + b;
  print(adder(2, 3)); // 5
  
  // Function به عنوان parameter
  int compute(int x, int Function(int) fn) {
    return fn(x);
  }
  print(compute(5, (n) => n * 2)); // 10
  
  // Anonymous function
  var doubled = [1, 2, 3].map((n) => n * 2).toList();
  print(doubled); // [2, 4, 6]
  
  // Closures
  Function makeCounter() {
    int count = 0;
    return () {
      count++;
      return count;
    };
  }
  
  var counter = makeCounter();
  print(counter()); // 1
  print(counter()); // 2
  print(counter()); // 3
}

// 6. Generic functions
T firstOrDefault(List items, T defaultValue) {
  return items.isEmpty ? defaultValue : items.first;
}

// 7. Higher-order functions
List mapList(List items, R Function(T) mapper) {
  return items.map(mapper).toList();
}
    

۲.۶ Collections


void main() {
  // === LIST ===
  List numbers = [1, 2, 3, 4, 5];
  var fruits = ["سیب", "موز", "پرتقال"];
  
  // متدهای پرکاربرد
  fruits.add("انگور");                    // اضافه
  fruits.remove("موز");                   // حذف
  fruits.contains("سیب");                 // true
  fruits.length;                          // 3
  fruits[0];                              // "سیب"
  fruits.first;                           // "سیب"
  fruits.last;                            // "انگور"
  fruits.isEmpty;                         // false
  
  // Map، filter، reduce
  var doubled = numbers.map((n) => n * 2).toList();        // [2,4,6,8,10]
  var even = numbers.where((n) => n.isEven).toList();      // [2,4]
  var sum = numbers.reduce((a, b) => a + b);               // 15
  var total = numbers.fold(100, (acc, n) => acc + n);      // 115
  
  // sort
  numbers.sort();                                          // [1,2,3,4,5]
  numbers.sort((a, b) => b.compareTo(a));                  // [5,4,3,2,1]
  
  // === SET (مجموعه - بدون تکرار) ===
  Set colors = {"red", "green", "blue"};
  colors.add("red");  // duplicate ignored
  print(colors.length); // 3
  
  // === MAP (key-value) ===
  Map ages = {
    "علی": 35,
    "محمد": 28,
    "زهرا": 30,
  };
  
  ages["علی"];                            // 35
  ages["نامشخص"];                         // null
  ages.containsKey("علی");                // true
  ages["جدید"] = 25;                      // اضافه
  ages.remove("محمد");                    // حذف
  
  // iteration
  ages.forEach((name, age) {
    print("$name: $age");
  });
  
  for (var entry in ages.entries) {
    print("${entry.key} = ${entry.value}");
  }
  
  // === Spread Operator ===
  var list1 = [1, 2, 3];
  var list2 = [0, ...list1, 4, 5];          // [0,1,2,3,4,5]
  var maybeNull = null;
  var list3 = [1, ...?maybeNull, 4];        // [1,4]
  
  // === Collection if/for ===
  bool isLogged = true;
  var nav = [
    "Home",
    "Products",
    if (isLogged) "Profile",
    if (isLogged) "Logout" else "Login",
  ];
  
  var items = [1, 2, 3];
  var doubled2 = [for (var i in items) i * 2];  // [2,4,6]
}
    

۲.۷ Class‌ها


// 1. کلاس ساده
class Person {
  // فیلدها
  String name;
  int age;
  
  // Constructor
  Person(this.name, this.age);
  
  // Method
  String introduce() => "نام: $name، سن: $age";
}

void main() {
  var p = Person("علی", 35);
  print(p.introduce());
}

// 2. Named Constructor
class Point {
  double x;
  double y;
  
  Point(this.x, this.y);
  
  // Named constructor
  Point.origin() : x = 0, y = 0;
  
  // با initializer list
  Point.fromList(List coords)
      : x = coords[0],
        y = coords[1];
}

var origin = Point.origin();
var p2 = Point.fromList([3.0, 4.0]);

// 3. Const Constructor (immutable objects)
class Color {
  final int r, g, b;
  
  // فیلدها باید final باشند
  const Color(this.r, this.g, this.b);
  
  static const red = Color(255, 0, 0);
  static const green = Color(0, 255, 0);
}

const c = Color(100, 100, 100);  // می‌تواند const باشد

// 4. Getters و Setters
class Rectangle {
  double width;
  double height;
  
  Rectangle(this.width, this.height);
  
  // Getter
  double get area => width * height;
  double get perimeter => 2 * (width + height);
  
  // Setter
  set diagonal(double d) {
    final ratio = width / height;
    height = d / sqrt(1 + ratio * ratio);
    width = height * ratio;
  }
}

// 5. Static members
class MathUtils {
  static const double pi = 3.14159;
  
  static double square(double x) => x * x;
}

print(MathUtils.pi);
print(MathUtils.square(5)); // 25.0

// 6. Private members (با _)
class BankAccount {
  String _accountNumber;  // private (فقط در همین library)
  double _balance;
  
  BankAccount(this._accountNumber, this._balance);
  
  double get balance => _balance;
  
  void deposit(double amount) {
    if (amount > 0) _balance += amount;
  }
}
    

۲.۸ Inheritance، Mixins، Interfaces


// 1. Inheritance با extends
class Animal {
  String name;
  Animal(this.name);
  
  void eat() => print("$name در حال خوردن است");
  void sleep() => print("$name در حال خوابیدن است");
}

class Dog extends Animal {
  Dog(super.name);  // Dart 3: super parameter
  
  void bark() => print("$name: واق واق!");
  
  // Override
  @override
  void eat() {
    super.eat();  // فراخوانی parent
    print("استخوان دوست دارم");
  }
}

var d = Dog("رکس");
d.eat();   // رکس در حال خوردن است / استخوان دوست دارم
d.bark();  // رکس: واق واق!
d.sleep(); // ارث‌بری شده

// 2. Abstract class (نمی‌توان instance ساخت)
abstract class Shape {
  String name;
  Shape(this.name);
  
  // abstract method (بدون بدنه)
  double area();
  
  void describe() {
    print("$name با مساحت ${area()}");
  }
}

class Circle extends Shape {
  double radius;
  Circle(this.radius) : super("دایره");
  
  @override
  double area() => 3.14159 * radius * radius;
}

// 3. Interface (هر class می‌تواند interface باشد)
class Printable {
  void print() {}  // implementation default
}

class Document implements Printable {
  @override
  void print() {
    // باید همه methods پیاده شوند
    println("چاپ document");
  }
}

// 4. Mixins (composition - بهترین قسمت Dart!)
mixin Walking {
  void walk() => print("راه می‌رود");
}

mixin Swimming {
  void swim() => print("شنا می‌کند");
}

mixin Flying {
  void fly() => print("پرواز می‌کند");
}

class Duck extends Animal with Walking, Swimming, Flying {
  Duck(super.name);
}

var duck = Duck("دونالد");
duck.walk();  // ✅
duck.swim();  // ✅
duck.fly();   // ✅

// 5. Sealed class (Dart 3 - برای exhaustive pattern matching)
sealed class Result {
  const Result();
}

class Success extends Result {
  final T data;
  const Success(this.data);
}

class Failure extends Result {
  final String error;
  const Failure(this.error);
}

// با switch می‌توانید مطمئن شوید همه حالات handled شدند
String describe(Result result) {
  return switch (result) {
    Success(data: final d) => "موفق: $d",
    Failure(error: final e) => "خطا: $e",
  };
}
    

۲.۹ Async / Await

Dart برای کارهای ناهمزمان (network، file I/O) از Future و Stream استفاده می‌کند.


// === Future ===
Future fetchUser() async {
  // شبیه‌سازی API call
  await Future.delayed(Duration(seconds: 2));
  return "اطلاعات کاربر";
}

// با await
void main() async {
  print("شروع");
  String user = await fetchUser();
  print(user);
  print("پایان");
}

// با then
fetchUser()
    .then((user) => print(user))
    .catchError((e) => print("خطا: $e"))
    .whenComplete(() => print("تمام"));

// === مدیریت خطا ===
Future divide(int a, int b) async {
  if (b == 0) throw Exception("تقسیم بر صفر");
  return a ~/ b;
}

Future example() async {
  try {
    var result = await divide(10, 0);
    print(result);
  } on Exception catch (e) {
    print("خطای انتظار: $e");
  } catch (e) {
    print("خطای ناشناخته: $e");
  } finally {
    print("همیشه اجرا می‌شود");
  }
}

// === چند Future موازی ===
Future parallelExample() async {
  // اجرای موازی
  final results = await Future.wait([
    fetchUser(),
    fetchProducts(),
    fetchOrders(),
  ]);
  
  print(results); // [user, products, orders]
  
  // یا با timeout
  try {
    final user = await fetchUser().timeout(
      Duration(seconds: 5),
      onTimeout: () => "default",
    );
  } on TimeoutException catch (_) {
    print("timeout");
  }
}

// === Stream ===
// Stream = Future با چندین مقدار در طول زمان
Stream countdown(int from) async* {
  for (int i = from; i >= 0; i--) {
    await Future.delayed(Duration(seconds: 1));
    yield i;  // emit مقدار
  }
}

void streamExample() async {
  // listen
  await for (final n in countdown(5)) {
    print(n);  // 5, 4, 3, 2, 1, 0
  }
  
  // یا با subscription
  final subscription = countdown(3).listen(
    (n) => print("got $n"),
    onError: (e) => print("error $e"),
    onDone: () => print("done"),
  );
  
  // cancel در صورت نیاز
  // subscription.cancel();
}

// === استفاده در Flutter ===
// FutureBuilder برای Future
FutureBuilder(
  future: fetchUser(),
  builder: (context, snapshot) {
    if (snapshot.connectionState == ConnectionState.waiting) {
      return CircularProgressIndicator();
    }
    if (snapshot.hasError) {
      return Text("خطا: ${snapshot.error}");
    }
    return Text(snapshot.data ?? "");
  },
)

// StreamBuilder برای Stream
StreamBuilder(
  stream: countdown(10),
  builder: (context, snapshot) {
    return Text("${snapshot.data ?? 0}");
  },
)
    

۲.۱۰ Records و Pattern Matching (Dart 3)


// === Records (مثل tuple در Python) ===
void recordsExample() {
  // Positional record
  (int, String) tuple = (42, "hello");
  print(tuple.$1); // 42
  print(tuple.$2); // hello
  
  // Named record
  ({String name, int age}) person = (name: "علی", age: 35);
  print(person.name);
  print(person.age);
  
  // Mixed
  (int, String, {bool isActive}) item = (1, "محصول", isActive: true);
  
  // Return چند مقدار از function!
  (int, int) divmod(int a, int b) {
    return (a ~/ b, a % b);
  }
  
  var (quotient, remainder) = divmod(17, 5);
  print("$quotient remainder $remainder"); // 3 remainder 2
}

// === Pattern Matching ===
void patternsExample() {
  var json = {"name": "علی", "age": 35};
  
  // Destructuring map
  if (json case {"name": String name, "age": int age}) {
    print("$name، $age ساله");
  }
  
  // Destructuring list
  var list = [1, 2, 3];
  if (list case [int a, int b, int c]) {
    print("$a + $b + $c = ${a + b + c}");
  }
  
  // ...rest pattern
  if (list case [int first, ...var rest]) {
    print("اول: $first، بقیه: $rest");
  }
  
  // Switch expression (Dart 3)
  int classify(num value) => switch (value) {
    < 0 => -1,
    0 => 0,
    > 0 => 1,
    _ => 0,
  };
  
  // Switch با pattern
  String describe(Object obj) => switch (obj) {
    int i when i > 100 => "عدد بزرگ: $i",
    int i => "عدد: $i",
    String s when s.isEmpty => "رشته خالی",
    String s => "رشته: $s",
    List l => "لیست ${l.length} تایی",
    {"name": String n} => "object با name: $n",
    _ => "ناشناخته",
  };
  
  print(describe(42));           // عدد: 42
  print(describe(150));          // عدد بزرگ: 150
  print(describe("hello"));      // رشته: hello
  print(describe([1, 2, 3]));    // لیست 3 تایی
  print(describe({"name": "علی"})); // object با name: علی
}
    

۲.۱۱ Extension Methods

اضافه کردن method به class های موجود — بدون inheritance.


// extension روی String
extension StringExtensions on String {
  bool get isPersian {
    final persianRegex = RegExp(r"[u0600-u06FF]");
    return persianRegex.hasMatch(this);
  }
  
  String capitalize() {
    if (isEmpty) return this;
    return this[0].toUpperCase() + substring(1);
  }
  
  String truncate(int length) {
    if (this.length <= length) return this;
    return "${substring(0, length)}...";
  }
}

void main() {
  print("سلام".isPersian);              // true
  print("hello".capitalize());          // Hello
  print("This is a long text".truncate(10));  // This is a ...
}

// extension روی int
extension IntExtensions on int {
  bool get isEven2 => this % 2 == 0;
  
  Duration get seconds => Duration(seconds: this);
  Duration get minutes => Duration(minutes: this);
  Duration get hours => Duration(hours: this);
  Duration get days => Duration(days: this);
}

// استفاده شیک:
await Future.delayed(2.seconds);
final week = 7.days;

// extension generic
extension ListExtensions on List {
  T? get firstOrNull => isEmpty ? null : first;
  T? get lastOrNull => isEmpty ? null : last;
  
  List takeRandom(int count) {
    final shuffled = [...this]..shuffle();
    return shuffled.take(count).toList();
  }
}

[1, 2, 3, 4, 5].takeRandom(2);  // مثلاً [3, 1]
[].firstOrNull;                  // null
    

۲.۱۲ بهترین تجربیات Dart

  1. از final به‌صورت پیش‌فرض استفاده کنید. فقط وقتی نیاز به تغییر دارید var.
  2. Null safety را جدی بگیرید. از ! فقط با اطمینان کامل.
  3. Named parameters در Constructor. برای readability.
  4. Const constructors هر کجا ممکن. performance بهتر.
  5. Mixins برای code reuse. به جای multiple inheritance.
  6. Sealed classes برای exhaustive matching. در Dart 3.
  7. Records به جای Map ساده. type-safe و سریع‌تر.
  8. Extension methods. برای DSL های زیبا.
  9. Effective Dart را بخوانید. dart.dev/effective-dart
  10. Linter را فعال کنید. flutter_lints در pubspec.

۲.۱۳ خلاصه فصل

آنچه آموختیم:
  • متغیرها: var، final، const، late، dynamic
  • Null Safety با ?، ??، ??=، !
  • توابع: positional، optional، named، arrow، closures
  • Collections: List، Set، Map، spread، collection if/for
  • Class: constructors، getters، setters، static
  • OOP: inheritance، abstract، interface، mixin
  • Sealed class برای exhaustive matching
  • Async/Await، Future، Stream
  • Records و Pattern Matching در Dart 3
  • Extension methods برای code زیبا
در فصل بعد: Widget‌ها — قلب Flutter. StatelessWidget، StatefulWidget، Widget tree، lifecycle و BuildContext.

نمایش سایت

رنگ سایت
حالت نمایش
اندازهٔ متن
خوانایی

این تنظیمات فقط روی مرورگر شما ذخیره می‌شود.