This is the 26th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021
In the process of Android development, similar methods will be generated according to different parameter types through overloading, and base class methods can be further extracted through generics. For Dart, generics can be used to extract base classes for scenarios where objects are constructed in multiple ways. Today’s tip is to take a quick look at Generics in Dart;
// Android
public static void getValue(boolean value) {}
public static void getValue(int value) {}
public static void getValue(long value) {}
public static void getValue(String value) {}
Copy the code
Generics
Generics Generics are a way to address class/interface/method reuse and validate data against unspecified types; Usually use <… > symbol, where parameters are generally represented by T, E, S, K, V letters;
Generic advantage
Dart does not support overloading, so you can set multiple methods with different names or different named constructors.
bool getBoolValue(bool value) {}
bool saveIntValue(int value) {}
String saveStringValue(String value) {}
Copy the code
Therefore, this method needs to set up several similar methods, the code is too redundant; The types in Dart are actually optional, that is, function types in Dart can omit parameter types and variable types. Therefore, it tries not to specify the parameter type and return type, which can avoid code redundancy, but gives up code checking.
getValue(value) => value;
Copy the code
At this point, we can consider using generics approach, and the advantage of generics is that properly specified generics can help code generation and reduce code duplication to avoid code redundancy;
T getValue<T>(T value) => value; print('SpUtils -> getValue(bool) -> ${getValue(true)} -> ${getValue<bool>(true)}'); print('SpUtils -> getValue(int) -> ${getValue(123)} -> ${getValue<int>(123)}'); Print (' SpUtils - > getValue (String) - > ${getValue (' strategy o little monks')} - > ${getValue < String > (' strategy o little monks')} ");Copy the code
Generic method
The snip is to define a generic method for getValue, but generics can be used flexibly to restrict only parameters or return types or both;
1. Function parameters are generic types
GetValue () can be used as a normal function, but to limit parameter type validation, a fixed type can be inserted before the parameter; Because getValue is limited, the argument can only be passed as String. If it is passed as any other type, an exception will be raised.
getValue<T>(T value) => value; Print ('SpUtils -> getValue(String) -> ${getValue<String>(' SpUtils -> getValue ')}'); GetValue <String>(123) // The argument type int can't be assigned to The parameter type String.Copy the code
2. The function returns a generic type
When the generic restriction is added before getValue(), the returned parameter is restricted to be a generic type, and the returned content cannot be restricted to a fixed type. In this case, both the parameter and the returned value are checked for uncertain type.
T getValue<T>(T value) => value; Print ('SpUtils -> getValue(String) -> ${getValue<String>(' SpUtils -> getValue ')}');Copy the code
A generic class
The basic array types commonly used in Dart, such as List or Set, are generic classes. Using List as an example, I created a generic class for MyList.
class MyList<T> {
List _list = List<T>();
void add<T>(T value) {
this._list.add(value);
}
get myList => this._list;
}
Copy the code
You can add any type of data to MyList. If int or String data is restricted to be passed in, only fixed data can be passed in. Otherwise, an exception message will be displayed. That is, the uncertain type is verified by generics.
MyList myList1 = MyList(); myList1.add(true); myList1.add(123); Mylist1. add(' A Ce little Monk '); print('MyList -> ${myList1.myList}'); /// I/flutter (13273): MyList -> [true, 123, aace] MyList myList2 = MyList<int>(); myList2.add(true); // Only fixed int mylist2.add (123) can be passed; print('MyList -> ${myList2.myList}'); /// type 'bool' is not a subtype of type 'int' of 'value'Copy the code
A generic interface
Dart defines a generic interface in the same way as it defines a generic class. Dart defines an interface in either a generic class or an abstract class. Xiaocai defines an SP interface and adds get/set methods.
abstract class SP<T> { void set(String key, T value); T get(String key); } class SpUtils<T> implements SP<T> { Map map = new Map(); @override T get(String key) { return map[key]; } @override void set(String key, T value) { map[key] = value; }}Copy the code
If SpUtils is set to String, an exception will be raised if it is passed to any other type. If SpUtils is set to String, an exception will be raised.
SpUtils spUtils = SpUtils(); SpUtils. Set ('name', 'A Ce little Monk '); spUtils.set('age', 18); print('SpUtils -> ${spUtils.get('name')} -> ${spUtils.get('age')}'); // I/flutter (13273): SpUtils -> spUtils2 = SpUtils<String>(); // I/flutter (13273): SpUtils -> spUtils2 = SpUtils<String>(); Sputils2. set('name', 'Little Monk '); spUtils2.set('age', 18); Print ('SpUtils -> ${sputils2. get('name')} -> ${sputils2. get('age')}'); /// type 'int' is not a subtype of type 'String' of 'value'Copy the code
Generic constraint
When you use generic types, you can restrict their parameter types. For example, you can restrict them using extends. Extends limits its current parameter type and its subclass parameter type;
class Animal {} class FlyAnimal extends Animal {} class LandAnimal extends Animal {} class Bird extends FlyAnimal {} class Dog extends LandAnimal {} class Cat extends LandAnimal {} class Foo<T extends LandAnimal> {} Foo foo1 = Foo<LandAnimal>(); Foo foo2 = Foo<Cat>(); Foo foo3 = Foo<Dog>(); Foo foo4 = Foo<FlyAnimal>(); // exception type;Copy the code
Xiao CAI’s understanding of generics is limited to daily application, and his understanding of covariant/contravariant is not in place. If there are mistakes, please give more guidance!
Source: Little Monk A Ce