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");
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"));
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);
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"));
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);
}
๐๐ฒ๐ป๐ฒ๐ฟ๐ถ๐ฐ 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),
],
),
],
),
);
}
}
Top comments (0)