Consider the following function:
BasicClass copyWith({
String id,
}) {
// some code behaving differently for 1) id is undefined and 2) id is explicit null
}
And consider the two parameters below:
Nothing (id is undefined)
copyWith();
Null (id is null)
copyWith(id: null);
in the copyWith method, is there any way I can make it behave differently for 1) and 2)
There is no way to differentiate null from "no parameter passed".
The only workaround (which is used by Freezed to generate a copyWith that supports null) is to cheat using a custom default value:
final undefined = Object();
class Example {
Example({this.param});
final String param;
Example copyWith({Object param = undefined}) {
return Example(
param: param == undefined ? this.param : param as String,
);
}
}
This requires typing your variables as Object though.
To fix that issue, you can use inheritance to hide the Object under a type-safe interface (again, see Freezed):
final undefined = Object();
class Example {
Example._();
factory Example({String param}) = _Example;
String get param;
void method() {
print('$param');
}
Example copyWith({String param});
}
class _Example extends Example {
_Example({this.param}): super._();
final String param;
#override
Example copyWith({Object param = undefined}) {
return Example(
param: param == undefined ? this.param : param as String,
);
}
}
Related
The problem is the following.
I had a typescript factory class that I attempted to do in Dart:
class FactoryClass{
factory FactoryClass(dynamic types, String className, dynamic defaultValue){
if(types[className] != null ){
return types[className](defaultValue);
}
else{
throw Exception("");
}
}
}
In TS it was used like this:
let variable= new FactoryClass([String, Number, etc...], "Number", "42")
That in TypeScript would give back a Number type variable with the value 42
However, it's not gonna work in Dart since types have no constructor for this. So I can't do something like
final myString = new String("def_value")
So the question arises, how can I go about it in dart?
You can do similar in Dart with just functions:
typedef Factory = dynamic Function(dynamic value);
dynamic create(Map<String, Factory> types, String className, dynamic defaultValue) {
if (types.containsKey(className)) {
return types[className]!(defaultValue);
} else {
throw Exception("no factory for $className");
}
}
final factories = <String, Factory>{
'String': (s) => s.toString(),
'int': (i) => i is int ? i : int.parse('$i'),
'bool': (b) => b is bool ? b : ('$b' == 'true'),
};
show(v) => print('Value $v has type ${v.runtimeType}');
main() {
show(create(factories, 'String', 'foo'));
show(create(factories, 'int', '42'));
show(create(factories, 'bool', 'false'));
}
Prints:
Value foo has type String
Value 42 has type int
Value false has type bool
Contain method can not detect the object inside of list
What is the reason of that?
I expected to get the result of if block
enter image description hereLook at this picture as well.In the second picture it works
it's because your Contact object has no == relation between its instances,
so trying to compare two instances like this:
Contact(false, "") == Contact(false, "") // false
And the contains method follows the same comparison I did to find if a list contains that object.
It would help if you told Dart when two objects of that class should be considered equal to each other, by overriding the == operator like this:
class Country {
final bool? brotherCountry;
final String? name;
Country(this.brotherCountry, this.name);
#override
bool operator ==(covariant Country other) {
return other.name == name && other.brotherCountry ==brotherCountry;
}
}
now trying this:
Country(false, "") == Country(false, "") // true
and so on now the contains method will work as you expect
[Country(false, ""), Country(false, "test")].contains(Country(false, "")); // true
You can override the == operator on Country like so to get it to work:
class Country {
bool? brotherCountry;
String? name;
Country(this.brotherCountry, this.name);
#override
bool operator ==(Object other) {
if (other is Country) {
return name == other.name && brotherCountry == other.brotherCountry;
}
return false;
}
#override
int get hashCode => brotherCountry.hashCode ^ name.hashCode;
}
Alternatively, there's this package https://pub.dev/packages/equatable, and you can use it like so:
class Country extends Equtable {
bool? brotherCountry;
String? name;
Country(this.brotherCountry, this.name);
#override
List<Object> props => [brotherCountry, name];
}
As pointed about by jamesdlin, it's not because of call by value
From Effective dart, it says:
Any two objects that are equal must have the same hash code. Otherwise, maps and other hash-based collections will fail to recognize that the two objects are equivalent.
I am modelling a Dart class with the new null safety types in mind. I believe there are two effective ways to initialize non-nullable properties, calculated from a parameter.
For this example, we will use the Favourite class.
This class uses the initializer list in the constructor.
class Favourite {
int favouriteId;
Favourite({required this.favouriteId});
Favourite.mapFromJson(dynamic json)
: this.favouriteId = json["favouriteId"];
}
This class uses the 'late' keyword.
class Favourite {
late int favouriteId;
Favourite({required this.favouriteId});
Favourite.mapFromJson(dynamic json) {
this.favouriteId = json["favouriteId"];
}
}
When would you use one over the other? Using 'late' feels risky. If I added another named constructor, the compiler would not complain about 'favouriteId' not being initialized.
Are there other options?
Thank you!
Neither.
Use a default constructor that initializes the fields themselves and a factory constructor that handles deserializing the json object:
class Favourite {
final int favouriteId;
Favourite({required this.favouriteId});
factory Favourite.fromMap(Map<String, dynamic> map) {
final favouriteId = json['favouriteId'];
assert(favouriteId != null && favouriteId is int);
return Favourite(
favouriteId: favouriteId,
);
}
}
The late keyword can be a source of headache if you don't handle it properly, so in general don't use it unless you have to.
If you're sure the json will always have a "favouriteId", you can write it like this:
class Favourite {
int favouriteId;
Favourite({required this.favouriteId});
Favourite.mapFromJson(Map<String, dynamic?> json):
assert(() {
final favouriteId = json["favouriteId"];
return favouriteId != null && favouriteId is int;
}()),
favouriteId = json["favouriteId"] as int;
}
void main() {
dynamic m = {"favouriteId":2};
final favourite = Favourite.mapFromJson(m);
print("favourite id: ${favourite.favouriteId}");
}
There are several models have a same structure, { type: xxx, settings: xxx}, so i would like to use a parent class "WidgetConfig" with a generic type "T" to implement this, but problem occurs when i add "fromJson" methods. How can i invoke method on a generic type or any other ways to implement this?
class BannerWidgetViewModel extends ChangeNotifier {
WidgetConfig<BannerWidgetConfig> config;
BannerWidgetViewModel(String configJson){
config = WidgetConfig.fromJson(configJson);
}
}
class BannerWidgetConfig {
String imgUrl;
String padImgUrl;
String lessonId;
BannerWidgetConfig.fromJson(json){
if (json != null) {
this.imgUrl = json['imgUrl'];
this.padImgUrl = json['padImgUrl'];
this.lessonId = json['lessonId'];
}
}
}
class WidgetConfig<T> {
WidgetType type;
WidgetConfig.fromJson(json){
if (json != null) {
this.type = json['type'];
// this.settings = T.fromJson(json['settings']); // T doesn't have fromJson method
}
}
}
then i use a abstract class but still not working.
abstract class BaseWidgetConfig {
BaseWidgetConfig.fromJson(dynamic json);
}
class WidgetConfig<T extends BaseWidgetConfig> {
WidgetType type;
T settings;
WidgetConfig.fromJson(json){
if (json != null) {
this.type = json['type'];
this.settings = T.fromJson();
}
}
}
code picture
Directly show the function as a reference.
send function as a reference here.
FireStoreHelper.getList<ModelLesson>('grade4', ModelLesson.fromJson);
get the method here.
static Future<List<T>> getList<T>(String path, Function fromJson)
Consider a function in Dart file
void myFunction({int input = 1, Function(int, String) callback}) {
// ...
}
So, I wonder is it possible at all to specify a default value for the callback parameter, for instance it can be something like (_, _) => { }.
P.S. I know it has null as default value and ?? can help to avoid NPE, I'm just curious is it possible at all. Cheers.
You can do something like:
dynamic func(int i, String s) {
print(i.toString() + s);
}
void myFunction({int input = 1, Function(int, String) callback = func}) {
callback(input, " .");
}
void main() {
myFunction(input: 2);
}
The default value of an optional parameter must be constant.
This is what the documents said
This thing can be bypassed like this:
dynamic myCallback(int a,String b) {
}
void myFunction({int input = 1, Function(int, String) callback }) {
if (callback == null) callback = myCallback;
}
Edit:
Alternatively, you can use anonymos functaion with out myCallback funcation like this:
void myFunction({int input = 1, Function(int, String) callback }) {
if (callback == null) callback = (a,b){};
}