Dart
Links
Statements
for (var ix in list) { print(ix); }
for (var entry in list.entries) { print(entry.key + entry.value); }
for (int ix = 0; ix < 10; ix++) {}
while (doIt()){ }
do { } while(test());
switch(x) {
case '0':
case 'A': y=3; break;
case 'B': b=true; continue on_label_c; // Implementierung von "fall through"
on_label_c: case 'C': y=5; break;
default: break;
}
assert(str.isEmpty(), "String muss leer sein"); // nur im Debug aktiv.
Exception
try {
breedMoreLlamas();
} on OutOfLlamasException {
buyMoreLlamas();
} on Exception catch (e) {
print('Unknown exception: $e'); // Anything else that is an exception
} catch (e, stacktrace) {
print('Something really unknown: $e $stacktrace'); // No specified type, handles all
rethrow; // throw the same exception again
} finally {
cleanUp();
}
throw ArgumentError('not an int');
class MyException implements Exception{
String message;
MyException(this.message);
}
Class
abstract class BaseLogger {
int _errors = 0;
int _level;
static BaseLogger _lastInstance;
bool get isSilent => _level == 0; // getter
set isSilent(bool value) => _level = value ? 0 : 1; // setter
BaseLogger(this._level); // constructor
BaseLogger.silent() : this(0); // named constructor, "redirected constructor"
// abstract function:
void log(string message);
void error(string message){ _errors++; log('+++ ' + message); }
static BaseLogger lastInstance() { return _lastInstance; }
}
class Logger extends BaseLogger {
String _filename;
Logger(this._filename) : super(1);
/// weiterer Constructor:
Logger.silentLogger(this._filename): super.silent(0); // named constructor
/// Referenz auf vorigen Construktor:
Logger.fromConfig(String filename): this(Config(filename).getString('logFile'));
}
...
var logger = Logger('std.log'), logger2 = Logger.silentLogger('silent.log');
const logger2 = BaseLogger.lastInstance();
var isSilent = logger.isSilent;
Mixins
Mixins sind Klassen, die ihre Eigenschaften an andere Klassen ausleihen, aber nicht in die Klassenhierarchie eingebunden sind.
In anderen Sprachen wird das als Trait bezeichnet.
abstract class ErrorHandler {
final lastError = '';
// This class is intended to be used as a mixin, and should not be extended directly.
factory ErrorHandler._() => null;
void setError(String msg) => lastError = msg;
void print() => print('+++ $lastError');
}
class DoIt with ErrorHandler{
...
bool validate(String s){
if (s.isEmpty()){
setError('input is empty');
}
}
...
}
// Mehrere Mixins:
class A extends B with Errorhandler, MyMixin {
}
Enum
enum DataType { bool, int, string, customType } // Schlüsselwörter erlaubt!
DataType.values.forEach((v) => print('value: $v, index: ${v.index}'));
Interface
- Jede Klasse kann Interface sein. Dann muss jede Methode überschrieben werden
class D implements A, B, C {
@override
void doIt(){
// ...
}
}
Generator
Iterable<int> naturalsTo(int n) sync* {
int k = 0;
while (k < n) yield k++;
}
- ... und mit Rekursion:
Iterable<int> naturalsDownFrom(int n) sync* {
if (n > 0) {
yield n;
yield* naturalsDownFrom(n - 1);
}
}
Typen
- Casting:
final x = y as String;
typedef
Definiert eine Methodensignatur oder einen Typ-Alias:
typedef IntList = List<int>;
typedef Compare<T> = int Function(T a, T b);
# Alte Schreibweise:
typedef bool MyValidator(String input);
bool validate(MyValidator validator){
if (validator(input)) doIt();
}
Map
final map = <String, int>{ 'John': 1, 'Eve': 2 };
final knowsEve = map.containsKey('Eve') && map.containsValue(2);
map.remove('John');
map.removeWhere((k, v) => k.startsWith('J'));
final combinedMap1 = {...map1, ...map2};
map.forEach((k, v) { print('{ key: $k, value: $v }'); });
map.entries.forEach((e) { print('{ key: ${e.key}, value: ${e.value} }'); });
List
- Indizes: start: inklusiv end: exklusiv
final names = <String>['adam', 'bob', 'charly', 'eve'];
final names2 = [...names, 'judy'];
names.add('fred'); names.insert(3, 'chris');
ix = names.indexOf('bob'); ix2 = names.indexWhere((item) => item.startsWith('b'), start);
names.remove('bob'); names.removeAt(2);
names2 = names.getRange(2, 3);
name3 = names.sublist(ixStart, ixEnd);
print(names.first + ' ' + names.last);
names.firstWhere( (item) => item.length == 3);
names.replaceRange(1,3, ['john', 'judith']);
final first2Elements = names.take(2);
final allButFirst2Elements = names.skip(2);
names.followedBy(name2); // liefert names und die Iterables name2
names.any((item) => item.length < 3); // irgend ein Element mit der Bedingung
allLowerThan3 = names.every((item) => item.length < 3); // alle Elemente entsprechen der Bedingung
subList = names.where((item) => item[0] > 'k');
firstNameWithLength3 = names.firstWhere((item) => item.length==3, orElse: () => '<None>');
final summary = names.fold('names:', (prevValue, item) => prevValue += ' ' + item);
// fold(), reduce(), shuffle(), removeWhere(),
// foreach(), join(), contains()
DateTime
// Für DateFormat
import 'package:intl/intl.dart';
var now = new DateTime.now();
var moonLanding = DateTime.parse("1969-07-20 20:18:04Z");
var sixtyDaysFromNow = now.add(new Duration(days: 60));
final diffDays = sixtyDaysFromNow.difference(moonLanding).inDays;
var dateUtc = DateTime.utc(1944, 6, 6);
var local = dateUtc.toLocal();
var isBefore = now.before(sixtyDaysFromNow);
var linuxTime = now.millisecondsSinceEpoch ~/ 1000;
var date2 = DateTime.fromMillisecondsSinceEpoch(linuxTime * 1000);
test (date2.weekday == DateTime.monday /* 1 */ || date2.weekday == DateTime.sunday /* 7 */);
var formatter = DateFormat('yyyy.MM.dd HH:mm:ss dayOfWeek: E');
String formatted = formatter.format(now);
Set
var foundKeys = <String>{};
if (! foundKeys.contains('x')){
foundKeys.add('x');
}
// Iterable unique machen:
words.split(' ').toSet().toList();
RegExpr
<syntaxhighlight lang="dart">final regExpr = RegExp(r'(\w+)\s*=\s*(\d+)');
final matcher = regExpr.firstMatch('abc = 123');
if (matcher != null){
vars[matcher?.group(1)] = int.parse(matcher?.group(2) ?? 0);
} </source>
String
const limit = 3;
var interpreted = "Limit: $limit Time: ${time()}";
const x = "abc" + interpreted;
Konversion
final count = int.parse("123");
Formatierung
import 'package:sprintf/sprintf.dart';
sprintf("%02d %s", [1, "Hi"]);
print("${new DateTime.now().toString()}: $message\n");
Json
class Photo {
final int id;
final String title;
Photo({this.id, this.title});
factory Photo.fromJson(Map<String, dynamic> json) {
return Photo(
id: json['id'] as int,
title: json['title'] as String
);
}
final parse(){
final jsonData = '{ "name" : "Dane", "alias" : "FilledStacks" }';
final parsedJson = json.decode(jsonData);
}
}
Besonderheiten
- entweder optionale Positionsparameter oder optionale Namensparameter, nicht beide.
String substr(String str, int pos, [int length, bool uppercase]){ ... }
String substr2(String str, int pos, {int length, bool uppercase, Logger logger}){ ... }
x = substr('Hi world', 3, 2);
y = substr2('Hi world', 3, length:2, logger:logger);
// ..-Operator: Mehrfachzugriff auf voriges Objekt:
var person = Person()..name='Joe'..id=25;
var p = Point(10, -12)..setColor(green)..setWeight(1.22);
x ??= 5; // Zuweisung nur, wenn x==null
x ~/ 5 // Ganzzahlige Division
logger?.log() // Aufruf von log nur, wenn logger!=null
Reflection, Runtime-Info
if (a.runtimeType == int || a.runtimeType == String){...}
if (a is String || or a is Map || a is! List){...}
UnitTest
import 'import 'package:test/test.dart';
void main() {
group('Validators', () {
test('checkEmail', () {
expect(checkEmail('joe@example.com'), isNull);
expect(
checkEmail('joe@example@com'),
equals(
'Not an email address: joe@example@com Example: joe@example.com'));
});
isTrue equals(string) equalsIgnoringCase(string) startsWith(prefix) stringContainsInOrder(List<String> substrings) matches(regexp) isList isMapgreaterThan(v) greaterThanOrEqualTo(v) lessThan(v)