Pakete in Dart nutzen - flutter-tutorial-de/dart-programming GitHub Wiki

Table of Contents

Motivation

Ein Grundsatz der Programmierung lautet: Erfinde das Rad nicht nochmal!

Im Idealfall wird Programmcode für die Lösung eines Problems nur einmal auf der Welt geschrieben und gepflegt. Danach kann jeder diese Lösung benutzen, anstatt selbst eine Lösung zu erfinden.

Zu diesem Zweck gibt es in Dart sogenannte Pakete (englisch "packages").

Ein Paket ist eine Menge von Funktionen und/oder Klassen, die bestimmten Konventionen genügen, die hier jedoch nicht weiter erörtert werden.

Einbindung eines Paketes in den Quellcode

Syntax

import paketname_als_string ;

Beispiel

import 'dart:math';
void main(){
  print('sin(0.3): ${sin(0.3)}');
}
  • Einbinden des Paketes 'dart:math', das bei Dart automatisch mitgeliefert wird (deswegen "dart:").
  • Im Paket sind auch die trigonometrischen Funktionen wie sin() definiert. Daher ist der Aufruf sin(0.3) zulässig.
  • Ist die Anweisung import 'dart:math' nicht vorhanden, kommt die Fehlermeldung: "The function 'sin' isn't defined - line 3".
Warum ist das Paket nicht bei jedem Programm von Dart dabei?

Der Grund ist, dass der Compiler dadurch wesentlich langsamer werden würde. Denn er müsste stets alle Initialisierungen für alle Pakete durchführen, auch wenn das Paket nicht gebraucht wird. Auch wäre die Liste der Namen viel größer, was wiederum die Suche langsamer machen würde. Und ein Programm zum Zählen von Wörtern braucht beispielsweise keine mathematischen Funktionen usw.

Es gibt eine Reihe von Paketen, die bei Dart immer vorhanden sind. Die wichtigsten sind:

  • dart:async - Asynchrone Programmierung.
  • dart:collection - Weitere Container, z. B. doppelt verlinkte Listen.
  • dart:convert - Datenconvertierung, z. B. Bytes nach UTF-8.
  • dart:core - Das einzige Paket, das immer vorhanden ist, auch ohne Import: Enthält z. B. die Klasse String.
  • dart:math - Mathematische Funktionen, z. B. sin().
  • dart:io - Dateien, Verzeichnisse, Sockets...
  • dart:isolate - Parallelausführung ("Threads").
  • dart:html - Funktionen für die HTML-Bearbeitung, z. B. DOM-Elementypen.
Zur Beruhigung: Wem die obigen Begriffe nichts sagen, der wird sie wahrscheinlich auch in keinem Programm brauchen...

Zu diesen von Dart vorgegebenen Paketen kommen noch Pakete von anderen Quellen, z. B. https://pub.dev: Hier sind Tausende Pakete von verschiedenen Autoren gespeichert, die für sehr viele Aufgaben fertige Lösungen anbieten. Wir werden im Verlauf des Tutorials immer wieder darauf zurückgreifen.

Beispiel: Arbeiten mit Datum und Zeit

Hinweis: Dieses Beispiel kann unter Dartpad ausgeführt werden.

// import 'package:intl/intl.dart';
void main() {
  final dDay = DateTime(1944, 6, 6);
  final now = DateTime.now();
  print('Heute ist $now, der D-Day war am $dDay.');
  var moonLanding = DateTime.parse("1969-07-20 20:18:04Z");
  final diffDays = now.difference(moonLanding).inDays;
  final dayOfWeek = ',Mo,Di,Mi,Do,Fr,Sa,So'.split(',')[moonLanding.weekday];
  print('Die Mondlandung war vor $diffDays Tagen, ein $dayOfWeek.');
  final sevenDaysLater = now.add(Duration(days: 60));
  print('In einer Woche ist es $sevenDaysLater');
  final linuxTime = now.millisecondsSinceEpoch ~/ 1000;
  print(*Sekunden seit 1.1.1970: $linuxTime');
/*
  final formatter = DateFormat('yyyy.MM.dd HH:mm:ss');
  final formatted = formatter.format(now);
  print('Heute im Iso-Format: $formatted');
*/
}
  • Erste Zeile siehe unten.
  • DateTime(1944, 6, 6) liefert ein Objekt der Klasse DateTime mit den Parametern Jahr, Monat und Tag. Optional sind Stunde, Minute, Sekunde sowie Milli- und Mikrosekunden.
  • DateTime.now(); Es wird die statische Methode now() aufgerufen, die eine Instanz von DateTime abliefert mit den Angaben zum aktuellen Zeitpunkt.
  • 'Heute ist $now' Die Wandlung vom DateTime benutzt das amerikanische Format.
  • DateTime.parse("1969-07-20 20:18:04Z") So wandelt man einen String in ein DateTime-Objekt, mittels statischer Methode.
  • now.difference(moonLanding) liefert ein Objekt vom Type Duration, .inDays liefert das Attribut mit der Anzahl der Tage.
  • Das Attribut weekday liefert den Wochentag eines Datums als Zahl zwischen 1 und 7, 1 für Montag usw.
  • ',Mo,Di,Mi,Do,Fr,Sa,So'.split(',') spaltet den String in eine Liste mit 8 Elementen (erstes Element ist der Leerstring)
    • aus dieser Liste wird dann der String mit der Wochentagsnummer herausgepickt, der Name des Wochentags.
  • Die Methode add() erwartet als Parameter ein Objekt des Typs Duration und liefert die Addition dieser Dauer zu dem Zeitpunkt des aufrufenden DateTime-Objekts.
  • millisecondsSinceEpoch() liefert die Anzahl der Millisekunden seit dem "Beginn der Epoche", das ist der 01.01.1970, des aufrufendenden Objektes.
    • Der Operator ~/ ist die Ganzzahldivision, es wird also die Anzahl der Sekunden nach Epochenbeginn berechnet, das wird als "Linux-Zeit" bezeichnet.

Formatierung

Die erste und die letzten Zeilen sind auskommentiert, weil diese im dartpad.dev nicht ausführbar sind. In anderen Ausführungsumgebungen kann dieser Quellcode aber ausgeführt werden, wenn der Kommentar entfernt wird.

  • import "..." sorgt für die Verfügbarkeit der Klasse DateFormat.
  • formatter = DateFormat('yyyy.MM.dd HH:mm:ss') Der Konstruktor wird mit Platzhaltern angewiesen, wie das Format aussehen soll. yyyy steht für die vierstellige Jahreszahl, MM für zweistellige Monatsnummer, dd für den zweistelligen Tag im Monat usw.
  • Die Klasse leistet aber noch viel mehr: Es gibt Konstruktoren, die eine Lokalisierung des Datumsformats beherrschen, das Ergebnis der Formatierung passt dann zum eingestellten Ort (Länderkennung): DateFormat.yMd() liefert das Jahr, Monat und Tag in ortsspezifischer Reihenfolge.

Einbindung eines Paketes in ein Dart-Projekt

Ein Paket, das mit dart: beginnt, steht automatisch mit der Installation von Dart zur Verfügung.

Ein Paket, das mit package: beginnt muss extra in ein Projekt eingebunden werden. Das geschieht in der Datei pubspec.yaml im Projekt-Hauptverzeichnis.

Beispiel

Wir wollen das im vorigen Kapitel benannte Paket package:intl/intl.dart benutzen.

  • Dazu benötigen wir die aktuelle Versionsnummer: Wir gehen in einem Browser auf die Seite pub.dev
    • Dort geben wir in dem Suchfeld (mit Lupe) ein: intl.
    • Der erste Treffer ist das Paket intl. In der Beschreibung steht beispielsweise:
    • v 0.16.1 / 0.17.0-nullsafety.2 • Updated: Jan 6, 2020 [Published by a pub.dev verified publisher] dart.dev
    • Die Version ist hier also 0.16.1
  • In der Datei pubspec.yaml tragen wir nach dem Kommentar #Dependencies folgende Zeile ein:
  intl: ^0.16.1
  • Die Zeile muss mit zwei Leerzeichen beginnen, also kein Tabulatorzeichen!
  • Als Versionsnummer sollte die Nummer aus der obigen Beschreibung stehen
  • ^0.16.1 bedeutet: Die Version muss größer oder gleich der Version 0.16.1 sein, aber kleiner als die nächste Hauptversionsnummer, hier 1.0.0.
  • Weiter oben in der Datei steht eine Variante der Versionsangabe: sdk: '>=2.10.0 <3.0.0'. Hier muss die Version im angegebenen Bereich liegen, das ist nur eine besser dokumentierende Schreibweise von ^2.10.0

Lokale Referenz

Wenn ein referenziertes Paket noch nicht veröffentlicht ist, es aber lokal verfügbar ist, so wird es mit lokaler Pfadangabe in der *.yaml-Datei eingetragen. Es wird dabei das Verzeichnis mit der *.yaml-Datei des eingebundenen Pakets angegeben:

...
  dart_bones:
     path: ../dart_bones

Konvention Versionsnummern

Für Dart gilt die Konvention, dass eine Versionsnummer aus drei Nummern besteht, wobei die letzte "Nummer" noch mit Zusätzen ergänzt werden kann.

Beispiele: 1.0.0 4.7.12+7

  • Wenn eine Änderung stattfindet, die nicht abwärtskompatibel ist ("breaking change"), muss die erste oder die zweite Nummer hochgezählt werden.
  • Eine Neuerung erfordert das Hochzählen der dritten Nummer.
  • Ändert sich die API nicht, wird die Änderung mit +<zahl> dokumentiert.

Änderung in pubspec.yaml wirksam werden lassen

Ist in IdeaIC die Datei pubspec.yaml geöffnet, befinden sich über dem Dateiinhalt verschiedene Links. Mit dem Link Pub get wird das Werkzeug pub aufgerufen, das mit dem Argument get überprüft, ob alle Pakete aus der Datei schon zur Verfügung stehen. Wenn nicht, wird das Paket aus dem Netz heruntergeladen und integriert.

Ein Paket soll eine Aufgabe lösen, nur diese, diese Aufgabe aber gut!

Das bedeutet auch, dass Pakete selber andere Pakete benutzen können. Man spricht dann davon, dass das Paket A von Paket B abhängt. Das Werkzeug pub löst diese Abhängigkeiten auf, indem Pakete, die refererenziert werden, automatisch heruntergeladen werden, falls dies nicht schon vorher passiert ist. Dabei werden die Versionsnummern überprüft.

Probiere im Terminal (in Windows "Eingabeaufforderung") aus:

gdev dsuche
pub deps

Es wird eine Liste von Paketen mit Versionsnummern ausgegeben, die in dem Projekt zur Verfügung stehen.

⚠️ **GitHub.com Fallback** ⚠️