DEV Community

Cover image for Unlocking the Power of Generics in Dart: Using List, Set, Map, and Queue Collections
Esmaeil Ahmadipour
Esmaeil Ahmadipour

Posted on • Edited on

Unlocking the Power of Generics in Dart: Using List, Set, Map, and Queue Collections

Generics are a powerful feature of the Dart language that allow us to create collections that can only hold a single type of data. This ensures type safety and prevents us from accidentally adding the wrong type of data to a collection. Generics can be used with List, Set, Map, and Queue collections.

For example, a List can only hold strings, a Set can only hold integers, a Map can only hold key-value pairs where the key is a string and the value is an integer, and a Queue can only hold strings.

Using generics also allows us to easily access the data stored in a collection. For example, if we have a List we know that all of the elements in the list will be strings and we can easily access them without having to worry about type errors. Similarly, if we have a Map we know that all of the keys will be strings and all of the values will be integers and we can easily access them without having to worry about type errors.

1.๐—š๐—ฒ๐—ป๐—ฒ๐—ฟ๐—ถ๐—ฐ ๐—Ÿ๐—ถ๐˜€๐˜

In Dart, a List is simply an ordered group of objects. A list is simple an implementation of an array.

Example:

List<T> list = new List<String>();

list.add("John");

list.add("Mary");

list.add("Bob");
Enter fullscreen mode Exit fullscreen mode

2.๐—š๐—ฒ๐—ป๐—ฒ๐—ฟ๐—ถ๐—ฐ ๐—ฆ๐—ฒ๐˜

In Dart, a Set represents a collection of objects in which each object can exist only once.

Example:

Set<T> set = new Set<Product>();

set.add(new Product("Shirt"));

set.add(new Product("Pants"));

set.add(new Product("Hat"));
Enter fullscreen mode Exit fullscreen mode

3.๐—š๐—ฒ๐—ป๐—ฒ๐—ฟ๐—ถ๐—ฐ ๐— ๐—ฎ๐—ฝ

In Dart, Map is a dynamic collection of the key, value pairs.

Example:

Map<K, V> map = new Map<String, Customer>();

map["John"] = new Customer("John", 25);

map["Mary"] = new Customer("Mary", 30);

map["Bob"] = new Customer("Bob", 28);
Enter fullscreen mode Exit fullscreen mode

4.๐—š๐—ฒ๐—ป๐—ฒ๐—ฟ๐—ถ๐—ฐ ๐—ค๐˜‚๐—ฒ๐˜‚๐—ฒ

A queue is a collection that is used when the data is to be inserted in a FIFO (First in first out) manner. In Dat, a queue can be manipulated at both ends, i.e. at the start as well as the end of the queue.

Example:

Queue<T> queue = new Queue<Order>();

queue.add(new Order("Red Shirt"));

queue.add(new Order("Green Pants"));

queue.add(new Order("Blue Hat"));
Enter fullscreen mode Exit fullscreen mode

5. ๐—š๐—ฒ๐—ป๐—ฒ๐—ฟ๐—ถ๐—ฐ Class & ๐—š๐—ฒ๐—ป๐—ฒ๐—ฟ๐—ถ๐—ฐ Functions
Generics can also be used to create custom classes and functions. This allows us to create classes and functions that can be used with any type of data.

Example:

// ๐—š๐—ฒ๐—ป๐—ฒ๐—ฟ๐—ถ๐—ฐ Class
class MyClass<T> { 
T data;
 MyClass(this.data);
   void printData() {
     print(data); } 
} 

// ๐—š๐—ฒ๐—ป๐—ฒ๐—ฟ๐—ถ๐—ฐ Functions
void myFunction<T>(T data) {
   print(data); 
}

Enter fullscreen mode Exit fullscreen mode

๐—š๐—ฒ๐—ป๐—ฒ๐—ฟ๐—ถ๐—ฐ Example In Flutter
In below example, we have created a generic class called MyClass that can be used to store any type of data.
We have also created a object called WidgetListItem that takes a MyClass object and displays the data stored in it.
And we have used generics to ensure that the data stored in the MyClass object is of the correct type and that the WidgetListItem object can be used with any type of data.

import 'package:flutter/material.dart';

class MyClass<T,K> {
  Map<T,K>  data;
  Map<String,String>? type;

  MyClass(this.data, [this.type]) {
//The "type" variable is used to show "runtimeType" of the "MyClass" variables.
    type = {"${data.entries.first.key.runtimeType}":"${data.entries.first.value.runtimeType}"};
  }
}

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // We defines 3 object from generic classes
    MyClass universityName_term = MyClass<String,int>({"CentralUniversity":3});
    MyClass salary_tax = MyClass<int,double>({1000:0.09});
    MyClass firstName_lastName = MyClass<String,String>({"Esmaeil":"Ahmadipour"});

    return MaterialApp(
      title: 'Generics Demo',
      home: Scaffold(
        appBar: AppBar(title: const Text('Using Generics')),
        body: Center(
          child: Padding(
              padding: const EdgeInsets.all(48.0),
              child:Column(
                children: [
                  const WidgetListTitle(),
                  WidgetListItem(myClass: universityName_term,color: Colors.red.shade300),
                  WidgetListItem(myClass: salary_tax,color: Colors.green.shade300),
                  WidgetListItem(myClass: firstName_lastName,color: Colors.blue.shade300),
                ],
              )
          ),
        ),
      ),
    );
  }
}

class WidgetListTitle extends StatelessWidget {
  const WidgetListTitle({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.spaceBetween,
      children: const [
        Text('Map Side'),
        Text('Side Value'),
        Text('ValueType'),
      ],
    );
  }
}

class WidgetListItem extends StatelessWidget {
  const WidgetListItem({
    Key? key,
    required this.myClass, required this.color,
  }) : super(key: key);

  final MyClass myClass;
  final Color color;

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.all(8.0),
      color: color,
      child: Column(
        children: <Widget>[

          Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              const Text('Kay:'),
              Text('${myClass.data.entries.first.key}'),
              Text(myClass.type!.entries.first.key),
            ],
          ),
          const Divider(),
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              const Text('Value:'),
              Text('${myClass.data.entries.first.value}'),
              Text(myClass.type!.entries.first.value),
            ],
          ),
        ],
      ),
    );
  }
}

Enter fullscreen mode Exit fullscreen mode

Top comments (0)