Dart

Aus Info-Theke
Zur Navigation springen Zur Suche springen


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);

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

final regExpr = RegExp(r'(\w+)\s*=\s*(\d+)');
final matcher = reDisks.firstMatch(line);
if (matcher != null){
  vars[matcher.group(1)] = int.parse(matcher.group(2));
}

String

const limit = 3;
var interpreted = "Limit: $limit Time: ${time()}";

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'));
    });

Matcher:

isTrue equals(string) equalsIgnoringCase(string) startsWith(prefix) stringContainsInOrder(List<String> substrings) matches(regexp) isList isMapgreaterThan(v) greaterThanOrEqualTo(v) lessThan(v)