I have a function Future<T?> getDocById<T>(String id) aysnc {}, it gets the data from web and return the value with type T. How can I convert any incoming data from web to a given type?
use case - class User{ String name; User(this.name);}
now, await getDocById<User>() how can I convert the data to type User inside getDocById function? in another case - getDocById<Boo> it should get data from web and convert it to Boo and return
Since I just answered a similar question I am copying the code into here. However, if you have an unknown T incoming, you need to distinguish cases based on what is incoming. Without this you want be able to convert a bool or int into a String name.
Create a method in one of the classes
class A {
A(this.a);
final int a;
B toB() {
return B(
b: a,
}
}
class B {
B(this.b);
final int b;
}
To be used like final bInstance = aInstance.toB(); meaning you declared somewhere aInstance = A(1);
Related
I'm getting an error like
The expression doesn't evaluate to a function, so it can't be invoked.
Is there any workaround to achieve this I have different classes being returned from a map according to the key.
void main() {
Map<String, Type> map = {'user': User};
Type T = map['user']!;
User a = T(5);
print(a.id);
}
class User {
User(this.id);
final int id;
}
This question already has an answer here:
Is there a difference in how member variables are initialized in Dart?
(1 answer)
Closed 1 year ago.
I'm trying to understand the following example where I try to initialize a final variable in a constructor.
1st example - works
void main() {
Test example = new Test(1,2);
print(example.a); //print gives 1
}
class Test
{
final int a;
int b;
Test(this.a, this.b);
}
2nd example doesn't work
void main() {
Test example = new Test(1,2);
print(example.a); //compiler throws an error
}
class Test
{
final int a;
int b;
Test(int a, int b){
this.a = a;
this.b = b;
}
}
and when i remove final then it works again
void main() {
Test example = new Test(1,2);
print(example.a); //print gives 1
}
class Test
{
int a;
int b;
Test(int a, int b){
this.a = a;
this.b = b;
}
}
what is the difference between the constructor in the 1st and the 2nd constructor why final initialization works with the first and doesn't with the 2nd.
Can anyone explain that to me please?
THanks
You cannot instantiate final fields in the constructor body.
Instance variables can be final, in which case they must be set exactly once. Initialize final, non-late instance variables at declaration, using a constructor parameter, or using a constructor’s initializer list:
Declare a constructor by creating a function with the same name as
its class (plus, optionally, an additional identifier as described in
Named constructors). The most common form of constructor, the
generative constructor, creates a new instance of a class
syntax in the constructor (described in https://www.dartlang.org/guides/language/language-tour#constructors):
I have multiple class like this:-
Class A {
static int xyz = 10;
int c;
int d;
static A getData() {
// Do something
return A()..c = xyz*5;
}
Class B {
static int abc = 10;
int c;
static B getData() {
// Do something
return B()..c = xyz*5;
}
So, here you can see that the the getData() is doing the same thing, but have different return types.
Is there any way to avoid duplicate implementation like this, can it be done by defining a single function which can reference the class and have multiple return type?
This has two parts: creating the object, and assigning to a field of the object.
Creating the object, you are mostly out of luck. The only way to create an object of a specific type in a generic method is by using reflection via dart:mirrors. However, you have indicated that this is for a Flutter project, and Flutter doesn't support reflection, so that isn't an option. The only way you are going to be able to dynamically create an object is to pass in a factory method that the generic method can call to construct the object.
Assigning to a field of the object is easier, but it requires that you either lose static type checking by using dynamic or by tying your classes together with inheritance. The latter is the preferable choice, but if you are working with a library than it isn't always an option.
Combining these two things, the code will look like this:
class Foo {
static int xyz = 10;
int c;
}
class A extends Foo {
int d;
static A getData() {
return modifyObject(() => A());
}
}
class B extends Foo {
static B getData() {
return modifyObject(() => B());
}
}
T modifyObject<T extends Foo>(T create()) {
return create()..c = Foo.xyz * 5;
}
Before doing this, though, I'd take a look at whether your project actually needs it. If your use case is as simple as your example, I would argue that this level of generalization is overkill and you are hurting your code's readability more than you are helping its modularity.
So after dart made new keyword optional,
we can initialize an object with exact same syntax but different internal implementation.
class Color {
int r = 0, g = 0, b = 0;
Color({this.r, this.b, this.g});
//Named constructors
Color.red() //Implementation
Color.cyan() //Implementation
// Static Initializers
static Color red() => //Initialze with parameter
static Color cyan() => //Initialze with parameter
}
We can use them like this regardless of being it a named constructor or static method:
Color red = Color.red();
Color cyan = Color.cyan();
What is the place to use each of them?
In practice there is little difference between a factory constructor and a static method.
For a generic class, it changes where you can (and must) write a type parameter:
class Box<T> {
T value;
Box._(this.value);
factory Box.withValue(this.value) => Box<T>._(value);
static Box<T> fromValue<T>(T value) => Box<T>._(value);
}
...
var box1 = Box<int>.withValue(1);
var box2 = Box.fromValue<int>(2);
So, for generic classes, factory constructors are often what you want. They have the most pleasant syntax.
For non-generic classes, there is very little difference, so it's mainly about signaling intent. And deciding which category the name goes into in the DartDoc.
If the main objective of the function is to create a new object, make it a constructor.
If the main objective is to do some computation and eventually return an object (even if it's a new object), make it a static function.
That's why parse methods are generally static functions.
In short, do what feels right for your API.
Constructors and static functions are different. You usually create a named constructor that returns an instance of an object with some predefined values. For example, you have a class called Person which stores Name and Job. You can create this named constructor Person.doctor(name) which you will return a Person object with Job = 'doctor'
class Person{
final name;
final job;
Person(this.name, this.job);
Person.doctor(this.name, {this.job = "doctor"});
}
Static functions or variable persists on all the instance of a class. Let us say, Person has a static variable called count. You increment the count variable whenever an instance of Person is created. You can call Person.count anywhere later in your code to get the value of count (Number of instances of Person)
class Person{
final name;
final job;
static int count;
Person(this.name, this.job){
count++;
}
Person.doctor(this.name, {this.job = "doctor"});
}
Another very useful feature of static class methods is that you can make them asynchronous, i.e. wait for full initialisation in case this depends on some asynchronous operation:
Future<double> getCurrentPrice(String ticker) async {
double price;
// for example, fetch current price from API
price = 582.18;
return price;
}
class Stock {
String ticker;
double currentPrice=0.0;
Stock._(this.ticker);
static Future<Stock> stockWithCurrentPrice(String ticker) async {
Stock stock = Stock._(ticker);
stock.currentPrice = await getCurrentPrice (ticker);
return stock;
}
}
void main() async {
Stock stock = await Stock.stockWithCurrentPrice('AAPL');
print ('${stock.ticker}: ${stock.currentPrice}');
}
Another benefit of the distinction between named constructor and static function is that in the documentation generated the function will be either filed in the construction section or the methods section, which further makes it's intentions clearer to the reader.
A person looking for a constructor in the constructor section of the documentation will easily discover the named constructors as opposed to having to also dig through the static functions section too.
This question is about Dart language.
I want to have a class which is just a List but with some extra functionality.
For example I have a class named Model:
class Model{
String name;
int type;
Model(this.name, this.type);
}
I know that Model's type could take only four values: from 0 to 3.
And I want to have a method, which can give me a List of Models of specified type, e.g. List<Model> modelCollection.getByType(int type);.
I plan to to have four 'hidden' Lists of the Models (grouped by type) in that class.
Thus I need to override addition and removal of List elements to make that hidden lists being up to date.
How can I realize this as easy as possible?
P.S. I know this is quite simple, but I'm poorly familiar with Object inheritance and can't find proper examples.
P.P.S. I've also checked this but don't know is it outdated or not and didn't catch the idea.
To make a class implement List there are several ways :
Extending ListBase and implementing length, operator[], operator[]= and length= :
import 'dart:collection';
class MyCustomList<E> extends ListBase<E> {
final List<E> l = [];
MyCustomList();
void set length(int newLength) { l.length = newLength; }
int get length => l.length;
E operator [](int index) => l[index];
void operator []=(int index, E value) { l[index] = value; }
// your custom methods
}
Mixin ListMixin and implementing length, operator[], operator[]= and length= :
import 'dart:collection';
class MyCustomList<E> extends Base with ListMixin<E> {
final List<E> l = [];
MyCustomList();
void set length(int newLength) { l.length = newLength; }
int get length => l.length;
E operator [](int index) => l[index];
void operator []=(int index, E value) { l[index] = value; }
// your custom methods
}
Delegating to an other List with DelegatingList from the quiver package:
import 'package:quiver/collection.dart';
class MyCustomList<E> extends DelegatingList<E> {
final List<E> _l = [];
List<E> get delegate => _l;
// your custom methods
}
Depending on your code each of those options have their advantages. If you wrap/delegate an existing list you should use the last option. Otherwise use one of the two first options depending on your type hierarchy (mixin allowing to extend an other Object).
A basic approach is to extend an Object with IterableMixin. It also seems that you don't even need to override the "length" getter or let's say all methods that the IterableMixin already provides.
import 'dart:collection';
class Model {
String name;
int type;
Model(this.name, this.type) {
}
}
class ModelCollection extends Object with IterableMixin {
List<Model> _models;
Iterator get iterator => _models.iterator;
ModelCollection() {
this._models = new List<Model>();
}
//get one or the first type
Model elementByType(int type) {
for (Model model in _models) {
if (model.type == type) {
return model;
}
}
}
//get all of the same type
List<Model> elementsByType(int type) {
List<Model> newModel = new List<Model>();
for (Model model in _models) {
if (model.type == type) {
newModel.add(model);
}
}
return newModel;
}
add(Model model) {
this._models.add(model);
}
}
Excuse my strong static typing.
You might be interested in quiver.dart's Multimap. It behaves like a Map that allows multiple values per key.
Here's the code on github: https://github.com/google/quiver-dart/blob/master/lib/src/collection/multimap.dart#L20
It's on pub simply as quiver. We'll be hosting the dartdocs somewhere soon.