I have a final HashMap in a class, How can I have a default value for it?
class RoomsState {
final HashMap<int, int> myMap;
RoomsState({
this.myMap= const {}
});
}
as const {} is a Map and not HashMap I cannot do it, Also HashMap is not a const constructor
Not sure if this is the only way to do it, but it is an option:
import 'dart:collection';
class RoomsState {
final HashMap<int, int> myMap;
RoomsState({
HashMap<int, int>? myMap
}) : this.myMap = myMap ?? HashMap();
}
The myMap parameter are here nullable since we are using the null value to identify if we got any argument.
You could expect a Map in your constructor and then convert it to a HashMap in an initializer.
class RoomsState {
final HashMap<int, int> myMap;
RoomsState({
Map<int, int> map = const {},
}) : myMap = HashMap.from(map);
}
HashMap has the construtor of that creates a HashMap that contains all key/value pairs of other. Check this for reference.
Example:
HashMap<String, String> englishToFrench = HashMap.of({
"go": "aller",
"buy": "acheter",
"sleep": "dormir",
});
Usage example:
void main() {
print(englishToFrench["go"]);
}
Output:
aller
Related
How do I retrieve the first key from Gee.SortedMap in Vala?
For example if I have
Gee.SortedMap<int, string> foo = new Gee.TreeMap<int, string> ();
I want to get the first key, i.e. the lowest int in foo.
In Java we have java.util.SortedMap.firstKey(). I cannot find an equivalent in Vala.
The SortedMap has an ascending_keys property that returns a SortedSet. Then you can get the first() item from the SortedSet:
void main () {
Gee.SortedMap<int, string> foo = new Gee.TreeMap<int, string> ();
foo.set(2, "two");
foo.set(1, "one");
foo.set(0, "zero");
print(#"First sorted key: $(foo.ascending_keys.first())\n");
}
In java, if you want to initialize a static variable once, you can write code in Static Initialization Block just like this:
abstract class Dummy {
static final Map<String, object> cache = new HashMap();
static {
cache.add('foo', new Foo());
cache.add('bar', new Bar());
}
}
Here I want to ask if there have a similar way in Dart? What is the best coding practice in Dart programming?
abstract class Dummy {
static final Map<String, dynamic> cache = <String, dynamic>{};
}
Well, there is no static initialization block in dart, but there are some other approaches you could take here.
Firstly, if all you want to do is add a few items to a map, you can just use map literal syntax:
abstract class Dummy {
static final Map<String, dynamic> cache = <String, dynamic>{
'foo': Foo(),
'bar': Bar(),
};
}
Also if you just want to initialize a static value by calling a few methods on it, you can use cascade notation .., which for this specific example would look like this:
abstract class Dummy {
static final Map<String, dynamic> cache = <String, dynamic>{}
..['foo'] = Foo()
..['bar'] = Bar();
}
The above is using cascade to call the []= operator on the map instance, but you can call any method on the map instance using cascade. For example, I could also call the remove method:
abstract class Dummy {
static final Map<String, dynamic> cache = <String, dynamic>{}
..['foo'] = Foo()
..['bar'] = Bar()
..remove('foo');
}
I want to parse http response to Dart object,so I defined a abstract class
BaseBean:
abstract class BaseBean{
BaseBean.fromJson(Map<String, dynamic> json);
Map<String, dynamic> toJson();
}
And I used it in a function:
Future<ResultData<T>> netFetch<T extends BaseBean>(){
......
return new ResultData(T.fromJson(), result, code);
}
but T.fromJson() has an error:
The method 'fromJson' isn't defined for the class 'Type'
So,can I use generics in Dart like this?Is there a better way to solve this problem?
Yes, of course, it is possible, but only with a workaround:
T unmarshal<T>(Map map, {Type type}) {
if (type == null) {
type = T;
}
switch (type) {
case Order:
return Order.fromJson(map) as T;
case OrderItem:
return OrderItem.fromJson(map) as T;
case Product:
return Product.fromJson(map) as T;
default:
throw StateError('Unable to unmarshal value of type \'$type\'');
}
}
var order = unmarshal<Order>(data);
//
var product = unmarshal(data, type: Product) as Product;
//
var type = <String, Type>{};
types['OrderItem'] = OrderItem;
// ...
var type = types['OrderItem'];
var orderItem = unmarshal(data, type: type);
I used the same approach and I came to this solution.
I created a Map<Type, BaseBean Function(dynamic)> decoders.
It looks like
final decoders = {
MyClass: (data) => MyClass.fromJson(data),
};
and I get the function in this way
final MyClass myData = decoders[T]!(data);
You can also create a typedef for the BaseBean Function(dynamic) like this
typedef Decoder = BaseBean Function(dynamic);
So the Map<Type, BaseBean Function(dynamic)> will became Map<Type, Decoder>.
I was trying to use the compute function in Flutter.
void _blockPressHandler(int row, int col) async {
// Called when user clicks any block on the sudoku board . row and col are the corresponding row and col values ;
setState(() {
widget.selCol = col;
}
});
bool boardSolvable;
boardSolvable = await compute(SudokuAlgorithm.isBoardInSudoku , widget.board , widget.size) ;
}
isBoardInSudoku is a static method of class SudokuAlgorithm. Its present in another file. Writing the above code , tells me that
error: The argument type '(List<List<int>>, int) → bool' can't be assigned to the parameter type '(List<List<int>>) → bool'. (argument_type_not_assignable at [just_sudoku] lib/sudoku/SudokuPage.dart:161)
How do i fix this? Can it be done without bringing the SudokuAlgorithm class's methods out of its file ? How to send multiple arguments to the compute function ?
static bool isBoardInSudoku(List<List<int>>board , int size ){ } is my isBoardInSudoku function.
Just put the arguments in a Map and pass that instead.
There is no way to pass more than one argument to compute because it is a convenience function to start isolates which also don't allow anything but a single argument.
Use a map. Here is an example:
Map map = Map();
map['val1'] = val1;
map['val2'] = val2;
Future future1 = compute(longOp, map);
Future<double> longOp(map) async {
var val1 = map['val1'];
var val2 = map['val2'];
...
}
In OOP and in general, it is more elegant to create a class for that with fields you need, that gives you more flexibility and less hassle with hardcoded strings or constants for key names.
For example:
boardSolvable = await compute(SudokuAlgorithm.isBoardInSudoku , widget.board , widget.size) ;
replace with
class BoardSize{
final int board;
final int size;
BoardSize(this.board, this.size);
}
...
boardSolvable = await compute(SudokuAlgorithm.isBoardInSudoku, BoardSize(widget.board, widget.size)) ;
Use a Tuple
Here is some example code from my app:
#override
Future logChange(
String recordId, AttributeValue newValue, DateTime dateTime) async {
await compute(
logChangeNoCompute, Tuple2<String, AttributeValue>(recordId, newValue));
}
Future<void> logChangeNoCompute(Tuple2<String, AttributeValue> tuple) async {
_recordsById[tuple.item1]!.setAttributeValue(tuple.item2);
await storage.setItem(AssetsFileName, toJson());
}
You can have a function whose only argument is a Map so that you can pass multiple parameters by passing a Map with properties and values. However, the problem that I'm encountering now is that I cannot pass functions. If the value of a Map's property is a function I get an error when I run the compute function.
This example works(keep in mind that I've imported libraries and that's the reason why some functions and classes definitions aren't in this example)
Future<List<int>> getPotentialKeys({
#required int p,
#required int q,
})async{
return await compute(allKeys,{
"p" : p,
"q" : q,
});
}
List<int> allKeys(Map<String,dynamic> parameters){
AdvancedCipherGen key = AdvancedCipherGen();
List<int> possibleE = key.step1(p: parameters["p"], q: parameters["q"]);
return possibleE;
}
This does not work(same thing with a function as the value of a property thows an error)
Future<List<int>> getPotentialKeys({
#required int p,
#required int q,
#required Function(AdvancedCipherGen key) updateKey,
})async{
return await compute(allKeys,{
"p" : p,
"q" : q,
"updateKey" : updateKey,
});
}
List<int> allKeys(Map<String,dynamic> parameters){
AdvancedCipherGen key = AdvancedCipherGen();
List<int> possibleE = key.step1(p: parameters["p"], q: parameters["q"]);
//TODO: Update the key value through callback
parameters["updateKey"](key);
return possibleE;
}
easily use a Class, you can Also Use Map or List But using class is Better and Cleaner
class MyFunctionInput{
final int first;
final int second;
MyFunctionInput({required this.first,required this.second});
}
change your function like this
doSomething(MyFunctionInput input){
}
and use it like below
compute(doSomething,MyFunctionInput(first: 1, second: 4));
I created a const object at app.config.dart with the following code:
const configObj = const {
'webServer': const {
'appBaseHref' : "/"
},
'auth0': const {
'apiKey': "foo",
'domain': "bar",
'callbackUrl': "callback"
}
};
now in my main dart file I import the app.config.dart and I try to get the values there and now idea how to do that. configObj.auth0.apiKey produces the error EXCEPTION: Class 'ImmutableMap' has no instance getter 'auth0'.
so how do I do this ?
thanks!
Dart doesn't support to access map entries with .
It should be:
configObj['auth0']['apiKey'];
Alternatively you can create classes for your configuration like
class WebServerConfig {
final String appBaseHref;
const WebServerConfig(this.appBaseHref);
}
class Auth0Config {
final String apiKey;
final String domain;
final String callbackUrl;
const Auth0(this.apiKey, this.domain, this.callbackUrl);
}
class MyConfig {
final WebServerConfig webServer;
final Auth0Config auth0;
const MyConfig(this.webServer, this.auth0);
}
const configObj = const MyConfig(
const WebServerConfig("/"),
const Auth0Config(
"foo",
"bar",
"callback"
)
);
This way you also get proper auto-completion when you access the config properties and can use the simple . notation to access properties.