EMZETT.
Login

Kurz: type MeinFehler = object of CatchableError

Teil des Kurses Nim

Kapitel 6 von 8 im Kurs Nim. Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.

Ausnahmen

import std/strutils
 
type MeinFehler = object of CatchableError
 
proc pruefe(n: int): int =
  if n < 0: raise newException(MeinFehler, "negativ: " & $n)
  n
 
try:
  echo pruefe(3)
  echo pruefe(-1)
except MeinFehler as e:
  echo "Eigener Fehler: ", e.msg
finally:
  echo "aufgeräumt"
 
try:
  echo parseInt("abc")
except ValueError as e:
  echo "ValueError: ", e.msg
 
try:
  let a = @[1, 2, 3]
  echo a[10]
except IndexDefect as e:
  echo "Indexfehler abgefangen"
 
try:
  echo 10 div 0
except DivByZeroDefect:
  echo "durch null"
 
proc sicher(a, b: int): int =
  try: a div b
  except DivByZeroDefect: -1
echo sicher(10, 2), " ", sicher(1, 0)

Ausgabe:

3
Eigener Fehler: negativ: -1
aufgeräumt
ValueError: invalid integer: abc
Indexfehler abgefangen
durch null
5 -1

Option

Statt nil nutzt man Option[T] für Werte, die fehlen können:

import std/options
 
proc finde(l: seq[int], x: int): Option[int] =
  for i, v in l:
    if v == x: return some(i)
  none(int)
 
let l = @[5, 3, 9]
let a = finde(l, 9)
let b = finde(l, 7)
echo a, " ", b
echo a.isSome, " ", b.isNone
echo a.get, " ", b.get(-1)
if a.isSome: echo "Index: ", a.get
echo a.map(proc (i: int): int = i * 10)

Ausgabe:

some(2) none(int)
true true
2 -1
Index: 2
some(20)

Templates und Makros

Templates sind Textersetzung auf Syntaxebene, Makros bauen Syntaxbäume:

import std/macros
 
template wiederhole(n: int, rumpf: untyped) =
  for _ in 1..n:
    rumpf
 
template mitZeit(name: string, rumpf: untyped) =
  echo "Start ", name
  rumpf
  echo "Ende ", name
 
template `!=?`(a, b: untyped): bool = a != b
 
macro verdoppeln(ausdruck: untyped): untyped =
  result = quote do:
    `ausdruck` * 2
 
wiederhole(3):
  stdout.write "x "
echo ""
mitZeit("Rechnung"):
  echo 6 * 7
echo 1 !=? 2
echo verdoppeln(21)
 
macro zeigeAst(x: untyped): untyped =
  echo x.treeRepr
  result = newStmtList()
zeigeAst(1 + 2)
const quadrate = block:
  var t: array[5, int]
  for i in 0 ..< 5: t[i] = i * i
  t
echo quadrate

Ausgabe:

x x x
Start Rechnung
42
Ende Rechnung
true
42
[0, 1, 4, 9, 16]

Nebenläufigkeit

import std/[locks, atomics]
 
var
  zaehler: Atomic[int]
  sperre: Lock
  summe = 0
 
initLock(sperre)
 
proc arbeiter(n: int) {.thread.} =
  for i in 1..1000:
    zaehler.atomicInc
    withLock sperre:
      summe += 1
 
var threads: array[4, Thread[int]]
for i in 0 ..< 4:
  createThread(threads[i], arbeiter, i)
joinThreads(threads)
echo zaehler.load, " ", summe

Ausgabe:

4000 4000

Der Compiler braucht für Threads den Schalter --threads:on (ab Nim 2 Standard). Für Async-Code gibt es std/asyncdispatch, für Parallelität das Paket malebolgia/taskpools.

Merke

  • try/except/finally und raise newException(...) behandeln Fehler
  • Option[T] ersetzt fehlende Werte; some, none, get
  • template und macro erweitern die Sprache zur Übersetzungszeit
  • Threads mit createThread, Lock, Atomic; asynchron mit asyncdispatch

Übungsaufgabe

Schreibe ein Template unless, das einen Block ausführt, wenn eine Bedingung falsch ist.

Quiz zur Selbstkontrolle

?

  • Werte, die fehlen können, ohne nil (richtig)
  • Optionale Parameter
  • Kommandozeilenoptionen
  • Konfigurationsdateien

Weiter im Kurs

Zurück: Strings, Dateien und Datenformate

Weiter: Praxisprojekte

Alle Kapitel: Nim im Überblick