Dart: Unterschied zwischen den Versionen
Zur Navigation springen
Zur Suche springen
(19 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
Zeile 5: | Zeile 5: | ||
* https://codingwithjoe.com/dart-fundamentals-async-await | * https://codingwithjoe.com/dart-fundamentals-async-await | ||
* https://dartpad.dev | * https://dartpad.dev | ||
* [[ArgParser Dart]] | |||
= Statements = | = Statements = | ||
< | <syntaxhighlight lang=dart>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++) {} | for (int ix = 0; ix < 10; ix++) {} | ||
while (doIt()){ } | while (doIt()){ } | ||
Zeile 19: | Zeile 21: | ||
} | } | ||
assert(str.isEmpty(), "String muss leer sein"); // nur im Debug aktiv. | assert(str.isEmpty(), "String muss leer sein"); // nur im Debug aktiv. | ||
</ | </syntaxhighlight> | ||
== Exception == | == Exception == | ||
< | <syntaxhighlight lang=dart> | ||
try { | try { | ||
breedMoreLlamas(); | breedMoreLlamas(); | ||
Zeile 39: | Zeile 41: | ||
MyException(this.message); | MyException(this.message); | ||
} | } | ||
</ | </syntaxhighlight> | ||
= Class = | = Class = | ||
< | <syntaxhighlight lang=dart>abstract class BaseLogger { | ||
int _errors = 0; | int _errors = 0; | ||
int _level; | int _level; | ||
Zeile 67: | Zeile 69: | ||
const logger2 = BaseLogger.lastInstance(); | const logger2 = BaseLogger.lastInstance(); | ||
var isSilent = logger.isSilent; | var isSilent = logger.isSilent; | ||
</ | </syntaxhighlight> | ||
== Named constructors == | |||
<syntaxhighlight lang=dart> | |||
class Point { | |||
final double x; | |||
final double y; | |||
Point(this.x, this.y); | |||
// Named constructor | |||
Point.origin() | |||
: x = xOrigin, | |||
y = yOrigin; | |||
} | |||
</syntaxhighlight> | |||
=== 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. | |||
<syntaxhighlight lang=dart> | |||
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 { | |||
} | |||
</syntaxhighlight> | |||
=== Enum === | === Enum === | ||
< | <syntaxhighlight lang=dart>enum DataType { bool, int, string, customType } // Schlüsselwörter erlaubt! | ||
DataType.values.forEach((v) => print('value: $v, index: ${v.index}')); | DataType.values.forEach((v) => print('value: $v, index: ${v.index}')); | ||
</ | </syntaxhighlight> | ||
== Interface == | == Interface == | ||
* Jede Klasse kann Interface sein. Dann muss jede Methode überschrieben werden | * Jede Klasse kann Interface sein. Dann muss jede Methode überschrieben werden | ||
< | <syntaxhighlight lang=dart> | ||
class D implements A, B, C { | class D implements A, B, C { | ||
@override | @override | ||
Zeile 83: | Zeile 126: | ||
} | } | ||
} | } | ||
</ | </syntaxhighlight> | ||
== Generator == | == Generator == | ||
< | <syntaxhighlight lang=dart>Iterable<int> naturalsTo(int n) sync* { | ||
int k = 0; | int k = 0; | ||
while (k < n) yield k++; | while (k < n) yield k++; | ||
} | } | ||
</ | </syntaxhighlight> | ||
* ... und mit Rekursion: | * ... und mit Rekursion: | ||
< | <syntaxhighlight lang=dart>Iterable<int> naturalsDownFrom(int n) sync* { | ||
if (n > 0) { | if (n > 0) { | ||
yield n; | yield n; | ||
Zeile 98: | Zeile 141: | ||
} | } | ||
} | } | ||
</ | </syntaxhighlight> | ||
= Typen = | = Typen = | ||
* Casting: | * Casting: | ||
< | <syntaxhighlight lang=dart> | ||
final x = y as String; | final x = y as String; | ||
</ | </syntaxhighlight> | ||
== typedef == | == typedef == | ||
Definiert eine Methodensignatur: | Definiert eine Methodensignatur oder einen Typ-Alias: | ||
< | <syntaxhighlight lang=dart> | ||
typedef IntList = List<int>; | |||
typedef Compare<T> = int Function(T a, T b); | |||
# Alte Schreibweise: | |||
typedef bool MyValidator(String input); | |||
bool validate(MyValidator validator){ | bool validate(MyValidator validator){ | ||
if (validator(input)) doIt(); | if (validator(input)) doIt(); | ||
} | } | ||
</ | </syntaxhighlight> | ||
== Map == | == Map == | ||
< | <syntaxhighlight lang=dart>final map = <String, int>{ 'John': 1, 'Eve': 2 }; | ||
final knowsEve = map.containsKey('Eve') && map.containsValue(2); | final knowsEve = map.containsKey('Eve') && map.containsValue(2); | ||
map.remove('John'); | map.remove('John'); | ||
Zeile 124: | Zeile 168: | ||
map.forEach((k, v) { print('{ key: $k, value: $v }'); }); | map.forEach((k, v) { print('{ key: $k, value: $v }'); }); | ||
map.entries.forEach((e) { print('{ key: ${e.key}, value: ${e.value} }'); }); | map.entries.forEach((e) { print('{ key: ${e.key}, value: ${e.value} }'); }); | ||
</ | </syntaxhighlight> | ||
== List == | == List == | ||
* Indizes: start: inklusiv end: exklusiv | * Indizes: start: inklusiv end: exklusiv | ||
< | <syntaxhighlight lang=dart>final names = <String>['adam', 'bob', 'charly', 'eve']; | ||
final names2 = [...names, 'judy']; | |||
names.add('fred'); names.insert(3, 'chris'); | names.add('fred'); names.insert(3, 'chris'); | ||
ix = names.indexOf('bob'); ix2 = names.indexWhere((item) => item.startsWith('b'), start); | ix = names.indexOf('bob'); ix2 = names.indexWhere((item) => item.startsWith('b'), start); | ||
Zeile 141: | Zeile 186: | ||
names.followedBy(name2); // liefert names und die Iterables name2 | names.followedBy(name2); // liefert names und die Iterables name2 | ||
names.any((item) => item.length < 3); // irgend ein Element mit der Bedingung | names.any((item) => item.length < 3); // irgend ein Element mit der Bedingung | ||
names.every((item) => item.length < 3); // alle Elemente | 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); | final summary = names.fold('names:', (prevValue, item) => prevValue += ' ' + item); | ||
// fold(), reduce(), shuffle(), removeWhere(), | // fold(), reduce(), shuffle(), removeWhere(), | ||
// foreach(), join(), contains() | // foreach(), join(), contains() | ||
</ | </syntaxhighlight> | ||
== DateTime == | == DateTime == | ||
< | <syntaxhighlight lang=dart> | ||
// Für DateFormat | // Für DateFormat | ||
import 'package:intl/intl.dart'; | import 'package:intl/intl.dart'; | ||
Zeile 161: | Zeile 208: | ||
var linuxTime = now.millisecondsSinceEpoch ~/ 1000; | 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'); | var formatter = DateFormat('yyyy.MM.dd HH:mm:ss dayOfWeek: E'); | ||
String formatted = formatter.format(now); | String formatted = formatter.format(now); | ||
</ | </syntaxhighlight> | ||
== Set == | |||
<syntaxhighlight lang="dart"> | |||
var foundKeys = <String>{}; | |||
if (! foundKeys.contains('x')){ | |||
foundKeys.add('x'); | |||
} | |||
// Iterable unique machen: | |||
words.split(' ').toSet().toList(); | |||
</syntaxhighlight> | |||
== RegExpr == | == RegExpr == | ||
< | <syntaxhighlight lang=dart>final regExpr = RegExp(r'(\w+)\s*=\s*(\d+)'); | ||
final matcher = | final matcher = regExpr.firstMatch('abc = 123'); | ||
if (matcher != null){ | if (matcher != null){ | ||
vars[matcher.group(1)] = int.parse(matcher.group(2)); | vars[matcher?.group(1)] = int.parse(matcher?.group(2) ?? 0); | ||
} | } | ||
</ | </syntaxhighlight> | ||
== String == | == String == | ||
< | <syntaxhighlight lang=dart> | ||
const limit = 3; | const limit = 3; | ||
var interpreted = "Limit: $limit Time: ${time()}"; | var interpreted = "Limit: $limit Time: ${time()}"; | ||
</ | const x = "abc" + interpreted; | ||
</syntaxhighlight> | |||
=== Konversion === | === Konversion === | ||
< | <syntaxhighlight lang=dart>final count = int.parse("123"); | ||
</ | </syntaxhighlight> | ||
=== Formatierung === | === Formatierung === | ||
< | <syntaxhighlight lang=dart>import 'package:sprintf/sprintf.dart'; | ||
sprintf("%02d %s", [1, "Hi"]); | sprintf("%02d %s", [1, "Hi"]); | ||
print("${new DateTime.now().toString()}: $message\n"); | print("${new DateTime.now().toString()}: $message\n"); | ||
</ | </syntaxhighlight> | ||
== Bytes == | |||
<syntaxhighlight lang=dart> | |||
import 'dart:convert'; | |||
String foo = 'Hello world'; | |||
List<int> bytes = utf8.encode(foo); | |||
String foo2 = utf8.decode(bytes); | |||
</syntaxhighlight> | |||
= Json = | = Json = | ||
< | <syntaxhighlight lang=dart>class Photo { | ||
final int id; | final int id; | ||
final String title; | final String title; | ||
Zeile 205: | Zeile 274: | ||
} | } | ||
} | } | ||
</ | </syntaxhighlight> | ||
= Besonderheiten = | = Besonderheiten = | ||
* entweder optionale Positionsparameter oder optionale Namensparameter, nicht beide. | * entweder optionale Positionsparameter oder optionale Namensparameter, nicht beide. | ||
< | <syntaxhighlight lang=dart>String substr(String str, int pos, [int length, bool uppercase]){ ... } | ||
String substr2(String str, int pos, {int length, bool uppercase, Logger logger}){ ... } | String substr2(String str, int pos, {int length, bool uppercase, Logger logger}){ ... } | ||
x = substr('Hi world', 3, 2); | x = substr('Hi world', 3, 2); | ||
Zeile 219: | Zeile 288: | ||
x ~/ 5 // Ganzzahlige Division | x ~/ 5 // Ganzzahlige Division | ||
logger?.log() // Aufruf von log nur, wenn logger!=null | logger?.log() // Aufruf von log nur, wenn logger!=null | ||
</ | </syntaxhighlight> | ||
== Reflection, Runtime-Info == | == Reflection, Runtime-Info == | ||
< | <syntaxhighlight lang=dart>if (a.runtimeType == int || a.runtimeType == String){...} | ||
if (a is String || or a is Map || a is! List){...} | if (a is String || or a is Map || a is! List){...} | ||
</ | </syntaxhighlight> | ||
== UnitTest == | == UnitTest == | ||
< | <syntaxhighlight lang=dart>import 'package:test/test.dart'; | ||
void main() { | void main() { | ||
group('Validators', () { | group('Validators', () { | ||
Zeile 239: | Zeile 308: | ||
}); | }); | ||
</ | </syntaxhighlight> | ||
[https://dartdoc.takyam.com/articles/dart-unit-tests/#matchers Matcher]: | [https://dartdoc.takyam.com/articles/dart-unit-tests/#matchers Matcher]: | ||
<pre> | |||
isTrue | isTrue | ||
equals(string) | equals(string) | ||
Zeile 252: | Zeile 321: | ||
greaterThanOrEqualTo(v) | greaterThanOrEqualTo(v) | ||
lessThan(v) | lessThan(v) | ||
</pre> | |||
== Async-Pattern == | |||
<syntaxhighlight lang=dart> | |||
Future<bool> hasSubDirs(String path) async { | |||
var rc = false; | |||
final subdir = Directory(path); | |||
await for (var entry in subdir.list()){ | |||
if (await Directory.isDirectory(entry.path)){ | |||
rc = true; | |||
break; | |||
} | |||
} | |||
return rc; | |||
} | |||
</syntaxhighlight> |
Aktuelle Version vom 29. Januar 2023, 13:18 Uhr
Links[Bearbeiten]
- DartAsynchron
- https://codingwithjoe.com/dart-fundamentals-async-await
- https://dartpad.dev
- ArgParser Dart
Statements[Bearbeiten]
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[Bearbeiten]
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[Bearbeiten]
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;
Named constructors[Bearbeiten]
class Point {
final double x;
final double y;
Point(this.x, this.y);
// Named constructor
Point.origin()
: x = xOrigin,
y = yOrigin;
}
Mixins[Bearbeiten]
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[Bearbeiten]
enum DataType { bool, int, string, customType } // Schlüsselwörter erlaubt!
DataType.values.forEach((v) => print('value: $v, index: ${v.index}'));
Interface[Bearbeiten]
- Jede Klasse kann Interface sein. Dann muss jede Methode überschrieben werden
class D implements A, B, C {
@override
void doIt(){
// ...
}
}
Generator[Bearbeiten]
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[Bearbeiten]
- Casting:
final x = y as String;
typedef[Bearbeiten]
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[Bearbeiten]
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[Bearbeiten]
- 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[Bearbeiten]
// 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[Bearbeiten]
var foundKeys = <String>{};
if (! foundKeys.contains('x')){
foundKeys.add('x');
}
// Iterable unique machen:
words.split(' ').toSet().toList();
RegExpr[Bearbeiten]
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);
}
String[Bearbeiten]
const limit = 3;
var interpreted = "Limit: $limit Time: ${time()}";
const x = "abc" + interpreted;
Konversion[Bearbeiten]
final count = int.parse("123");
Formatierung[Bearbeiten]
import 'package:sprintf/sprintf.dart';
sprintf("%02d %s", [1, "Hi"]);
print("${new DateTime.now().toString()}: $message\n");
Bytes[Bearbeiten]
import 'dart:convert';
String foo = 'Hello world';
List<int> bytes = utf8.encode(foo);
String foo2 = utf8.decode(bytes);
Json[Bearbeiten]
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[Bearbeiten]
- 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[Bearbeiten]
if (a.runtimeType == int || a.runtimeType == String){...}
if (a is String || or a is Map || a is! List){...}
UnitTest[Bearbeiten]
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)
Async-Pattern[Bearbeiten]
Future<bool> hasSubDirs(String path) async {
var rc = false;
final subdir = Directory(path);
await for (var entry in subdir.list()){
if (await Directory.isDirectory(entry.path)){
rc = true;
break;
}
}
return rc;
}