mirror of
https://github.com/adambard/learnxinyminutes-docs.git
synced 2024-12-25 16:23:37 +03:00
359 lines
9.2 KiB
Nix
359 lines
9.2 KiB
Nix
|
---
|
|||
|
language: nix
|
|||
|
filename: learnnix-de.nix
|
|||
|
contributors:
|
|||
|
- ["Chris Martin", "http://chris-martin.org/"]
|
|||
|
translators:
|
|||
|
- ["Dennis Keller", "https://github.com/denniskeller"]
|
|||
|
lang: de-de
|
|||
|
---
|
|||
|
|
|||
|
Nix ist eine simple funktionale Programmiersprache, die für den
|
|||
|
[Nix package manager](https://nixos.org/nix/) und
|
|||
|
[NixOS](https://nixos.org/) entwickelt wurde.
|
|||
|
|
|||
|
Du kannst Nix Ausdrücke evaluieren mithilfe von
|
|||
|
[nix-instantiate](https://nixos.org/nix/manual/#sec-nix-instantiate)
|
|||
|
oder [`nix-repl`](https://github.com/edolstra/nix-repl).
|
|||
|
|
|||
|
```
|
|||
|
with builtins; [
|
|||
|
|
|||
|
# Kommentare
|
|||
|
#=========================================
|
|||
|
|
|||
|
# Inline Kommentare sehen so aus.
|
|||
|
|
|||
|
/* Multizeilen Kommentare
|
|||
|
sehen so aus. */
|
|||
|
|
|||
|
|
|||
|
# Booleans
|
|||
|
#=========================================
|
|||
|
|
|||
|
(true && false) # Und
|
|||
|
#=> false
|
|||
|
|
|||
|
(true || false) # Oder
|
|||
|
#=> true
|
|||
|
|
|||
|
(if 3 < 4 then "a" else "b") # Bedingungen
|
|||
|
#=> "a"
|
|||
|
|
|||
|
|
|||
|
# Integers
|
|||
|
#=========================================
|
|||
|
|
|||
|
# Integers sind die einzigen numerischen Typen.
|
|||
|
|
|||
|
1 0 42 (-3) # Einige integers
|
|||
|
|
|||
|
(4 + 6 + 12 - 2) # Addition
|
|||
|
#=> 20
|
|||
|
|
|||
|
(7 / 2) # Division
|
|||
|
#=> 3
|
|||
|
|
|||
|
|
|||
|
# Strings
|
|||
|
#=========================================
|
|||
|
|
|||
|
"String Literale sind in Gänsefüßchen."
|
|||
|
|
|||
|
"
|
|||
|
String Literale können mehrere
|
|||
|
Zeilen umspannen.
|
|||
|
"
|
|||
|
|
|||
|
''
|
|||
|
Dies wird als Literal mit eingerückten String bezeichnet.
|
|||
|
Es entfernt intelligent führende Leerzeichen.
|
|||
|
''
|
|||
|
|
|||
|
''
|
|||
|
a
|
|||
|
b
|
|||
|
''
|
|||
|
#=> "a\n b"
|
|||
|
|
|||
|
("ab" + "cd") # String Konkatenation
|
|||
|
#=> "abcd"
|
|||
|
|
|||
|
# Mit Antiquotation kannst du Werte in Strings einbetten.
|
|||
|
("Dein Homeverzeichnis ist ${getEnv "HOME"}")
|
|||
|
#=> "Dein Homeverzeichnis ist /home/alice"
|
|||
|
|
|||
|
|
|||
|
# Paths
|
|||
|
#=========================================
|
|||
|
|
|||
|
# Nix besitzt einen primitven Datentyp für Pfade
|
|||
|
/tmp/tutorials/learn.nix
|
|||
|
|
|||
|
# Ein relativer Pfad wird beim Parsing zu einem absoluten Pfad aufgelöst,
|
|||
|
# relativ zu der Datei in der es auftritt.
|
|||
|
tutorials/learn.nix
|
|||
|
#=> /the-base-path/tutorials/learn.nix
|
|||
|
|
|||
|
# Ein Pfad muss mindestens einen Schrägstrich enthalten. Ein Pfad für eine
|
|||
|
# Datei im selben Verzeichnis benötigt ein ./ Präfix.
|
|||
|
./learn.nix
|
|||
|
#=> /the-base-path/learn.nix
|
|||
|
|
|||
|
# Der / Operator muss von Leerraum umgeben sein wenn du dividieren möchtest.
|
|||
|
7/2 # Das ist ein Pfadliteral
|
|||
|
(7 / 2) # Das ist ein Integerliteral
|
|||
|
|
|||
|
|
|||
|
# Importe
|
|||
|
#=========================================
|
|||
|
|
|||
|
# Eine nix Datei besitzt einen einzelnen top-level Ausdruck mit keinen freien Variablen.
|
|||
|
# Ein Import-Ausdruck wird zum Wert der Datei, die importiert wird, ausgewertet.
|
|||
|
(import /tmp/foo.nix)
|
|||
|
|
|||
|
# Importe können ebenso mit Strings spezifiziert werden.
|
|||
|
(import "/tmp/foo.nix")
|
|||
|
|
|||
|
# Import Pfade müssen absolut sein. Pfadliterale
|
|||
|
# sind automatisch aufgelöst, das ist ein Ordnung.
|
|||
|
(import ./foo.nix)
|
|||
|
|
|||
|
# Jedoch passiert dies nicht mit Strings.
|
|||
|
(import "./foo.nix")
|
|||
|
#=> error: string ‘foo.nix’ doesn't represent an absolute path
|
|||
|
|
|||
|
|
|||
|
# Let
|
|||
|
#=========================================
|
|||
|
|
|||
|
# `let` Blöcke erlauben es uns Werte zu Variablen zu binden.
|
|||
|
(let x = "a"; in
|
|||
|
x + x + x)
|
|||
|
#=> "aaa"
|
|||
|
|
|||
|
# Bindungen können auf sich gegenseitig verweisen. Die Reihenfolge spielt
|
|||
|
# keine Rolle.
|
|||
|
(let y = x + "b";
|
|||
|
x = "a"; in
|
|||
|
y + "c")
|
|||
|
#=> "abc"
|
|||
|
|
|||
|
# Innere Bindungen überschatten Äußere.
|
|||
|
(let a = 1; in
|
|||
|
let a = 2; in
|
|||
|
a)
|
|||
|
#=> 2
|
|||
|
|
|||
|
|
|||
|
# Funktionen
|
|||
|
#=========================================
|
|||
|
|
|||
|
(n: n + 1) # Funktion, die 1 addiert
|
|||
|
|
|||
|
((n: n + 1) 5) # Dieselbe Funktion angewendet auf 5.
|
|||
|
#=> 6
|
|||
|
|
|||
|
# Es gibt keine spezielle Syntax für benannte Funktionen, aber sie
|
|||
|
# können mit `let` Blöcken, wie jeder andere Wert auch, gebunden werden.
|
|||
|
(let succ = (n: n + 1); in succ 5)
|
|||
|
#=> 6
|
|||
|
|
|||
|
# Eine Funktion hat genau ein Argument.
|
|||
|
# Mehrere Argumente können erreicht werden mithilfe von Currying.
|
|||
|
((x: y: x + "-" + y) "a" "b")
|
|||
|
#=> "a-b"
|
|||
|
|
|||
|
# Benannte Funktionsargumente gibt es auch. Diese werden wir einführen, nachdem wir uns Sets
|
|||
|
# angeschaut haben.
|
|||
|
|
|||
|
# Listen
|
|||
|
#=========================================
|
|||
|
|
|||
|
# Listen werden durck eckige Klammern gekennzeichnet.
|
|||
|
|
|||
|
(length [1 2 3 "x"])
|
|||
|
#=> 4
|
|||
|
|
|||
|
([1 2 3] ++ [4 5])
|
|||
|
#=> [1 2 3 4 5]
|
|||
|
|
|||
|
(concatLists [[1 2] [3 4] [5]])
|
|||
|
#=> [1 2 3 4 5]
|
|||
|
|
|||
|
(head [1 2 3])
|
|||
|
#=> 1
|
|||
|
(tail [1 2 3])
|
|||
|
#=> [2 3]
|
|||
|
|
|||
|
(elemAt ["a" "b" "c" "d"] 2)
|
|||
|
#=> "c"
|
|||
|
|
|||
|
(elem 2 [1 2 3])
|
|||
|
#=> true
|
|||
|
(elem 5 [1 2 3])
|
|||
|
#=> false
|
|||
|
|
|||
|
(filter (n: n < 3) [1 2 3 4])
|
|||
|
#=> [ 1 2 ]
|
|||
|
|
|||
|
|
|||
|
# Sets
|
|||
|
#=========================================
|
|||
|
|
|||
|
# Ein "Set" ist eine ungeordnete Zuordnung mit Stringschlüsseln.
|
|||
|
{ foo = [1 2]; bar = "x"; }
|
|||
|
|
|||
|
# Der . Operator nimmt einen Wert aus dem Set.
|
|||
|
{ a = 1; b = 2; }.a
|
|||
|
#=> 1
|
|||
|
|
|||
|
# Der ? Operator testet, ob der Schlüssel in dem Set vorhanden ist.
|
|||
|
({ a = 1; b = 2; } ? a)
|
|||
|
#=> true
|
|||
|
({ a = 1; b = 2; } ? c)
|
|||
|
#=> false
|
|||
|
|
|||
|
# Der // Operator mergt zwei Sets.
|
|||
|
({ a = 1; } // { b = 2; })
|
|||
|
#=> { a = 1; b = 2; }
|
|||
|
|
|||
|
# Werte auf der rechten Seite überschrieben die Werte auf der linken Seite.
|
|||
|
({ a = 1; b = 2; } // { a = 3; c = 4; })
|
|||
|
#=> { a = 3; b = 2; c = 4; }
|
|||
|
|
|||
|
# Das Schlüsselwort rec bezeichenet ein "rekursives Set", in der sich Attribute
|
|||
|
# aufeinander beziehen können.
|
|||
|
(let a = 1; in { a = 2; b = a; }.b)
|
|||
|
#=> 1
|
|||
|
(let a = 1; in rec { a = 2; b = a; }.b)
|
|||
|
#=> 2
|
|||
|
|
|||
|
# Verschachetelte Sets können stückweise definiert werden.
|
|||
|
{
|
|||
|
a.b = 1;
|
|||
|
a.c.d = 2;
|
|||
|
a.c.e = 3;
|
|||
|
}.a.c
|
|||
|
#=> { d = 2; e = 3; }
|
|||
|
|
|||
|
# Die Nachkommen eines Attributs können in diesem Feld nicht zugeordnet werden, wenn
|
|||
|
# das Attribut selbst nicht zugeweisen wurde.
|
|||
|
{
|
|||
|
a = { b = 1; };
|
|||
|
a.c = 2;
|
|||
|
}
|
|||
|
#=> error: attribute ‘a’ already defined
|
|||
|
|
|||
|
|
|||
|
# With
|
|||
|
#=========================================
|
|||
|
|
|||
|
# Der Körper eines Sets Blocks wird mit der Zurodnung eines Satzes an die Variablen gebunden.
|
|||
|
(with { a = 1; b = 2; };
|
|||
|
a + b)
|
|||
|
# => 3
|
|||
|
|
|||
|
# Innere Bindungen überschatten äußere Bindungen.
|
|||
|
(with { a = 1; b = 2; };
|
|||
|
(with { a = 5; };
|
|||
|
a + b))
|
|||
|
#=> 7
|
|||
|
|
|||
|
# Die erste Linie diese Tutorials startet mit "with builtins;",
|
|||
|
# weil builtins ein Set mit allen eingebauten
|
|||
|
# Funktionen (length, head, tail, filter, etc.) umfasst.
|
|||
|
# Das erspart uns beispielseweise "builtins.length" zu schreiben,
|
|||
|
# anstatt nur "length".
|
|||
|
|
|||
|
|
|||
|
# Set patterns
|
|||
|
#=========================================
|
|||
|
|
|||
|
# Sets sind nützlich, wenn du mehrere Werte einer Funktion
|
|||
|
# übergeben musst.
|
|||
|
(args: args.x + "-" + args.y) { x = "a"; y = "b"; }
|
|||
|
#=> "a-b"
|
|||
|
|
|||
|
# Dies kann mit Hilfe von Set patterns deutlicher geschrieben werden.
|
|||
|
({x, y}: x + "-" + y) { x = "a"; y = "b"; }
|
|||
|
#=> "a-b"
|
|||
|
|
|||
|
# Standardmäßig schlägt das Muster bei Sets mit zusätzlichen Schlüsseln fehl.
|
|||
|
({x, y}: x + "-" + y) { x = "a"; y = "b"; z = "c"; }
|
|||
|
#=> error: anonymous function called with unexpected argument ‘z’
|
|||
|
|
|||
|
# Durch Hinzufügen von ", ..." können zusätzliche Schlüssel ignoriert werden.
|
|||
|
({x, y, ...}: x + "-" + y) { x = "a"; y = "b"; z = "c"; }
|
|||
|
#=> "a-b"
|
|||
|
|
|||
|
|
|||
|
# Errors
|
|||
|
#=========================================
|
|||
|
|
|||
|
# `throw` bewirkt, dass die Auswertung mit einer Fehlermeldung abgebrochen wird.
|
|||
|
(2 + (throw "foo"))
|
|||
|
#=> error: foo
|
|||
|
|
|||
|
# `tryEval` fängt geworfene Fehler.
|
|||
|
(tryEval 42)
|
|||
|
#=> { success = true; value = 42; }
|
|||
|
(tryEval (2 + (throw "foo")))
|
|||
|
#=> { success = false; value = false; }
|
|||
|
|
|||
|
# `abort` ist ähnlich wie throw, aber es ist fatal. Es kann nicht gefangen werden.
|
|||
|
(tryEval (abort "foo"))
|
|||
|
#=> error: evaluation aborted with the following error message: ‘foo’
|
|||
|
|
|||
|
# `assert` evaluiert zu dem gegebenen Wert, wenn die Bedingung wahr ist, sonst
|
|||
|
# löst es eine abfangbare Exception aus.
|
|||
|
(assert 1 < 2; 42)
|
|||
|
#=> 42
|
|||
|
(assert 1 > 2; 42)
|
|||
|
#=> error: assertion failed at (string):1:1
|
|||
|
(tryEval (assert 1 > 2; 42))
|
|||
|
#=> { success = false; value = false; }
|
|||
|
|
|||
|
|
|||
|
# Impurity
|
|||
|
#=========================================
|
|||
|
|
|||
|
# Da die Wiederholbarkeit von Builds für den Nix Packetmangager entscheidend ist,
|
|||
|
# werden in der Nix Sprache reine funktionale Elemente betont. Es gibt aber ein paar
|
|||
|
# unreine Elemente.
|
|||
|
# Du kannst auf Umgebungsvarialben verweisen.
|
|||
|
(getEnv "HOME")
|
|||
|
#=> "/home/alice"
|
|||
|
|
|||
|
# Die trace Funktion wird zum Debugging verwendet. Sie gibt das erste Argument zu stderr aus
|
|||
|
# und evaluiert das zweite Argument.
|
|||
|
(trace 1 2)
|
|||
|
#=> trace: 1
|
|||
|
#=> 2
|
|||
|
|
|||
|
# Du kannst Dateien in den Nix store schreiben. Obwohl unrein, kannst du dir relativ sicher sein,
|
|||
|
# dass es sicher ist, da der Dateiname aus dem Hash des Inhalts abgeleitet wird.
|
|||
|
# Du kannst Dateien von überall lesen. In diesem Beispiel schreiben wir Dateien in den Store
|
|||
|
# und lesen wieder davon.
|
|||
|
(let filename = toFile "foo.txt" "hello!"; in
|
|||
|
[filename (builtins.readFile filename)])
|
|||
|
#=> [ "/nix/store/ayh05aay2anx135prqp0cy34h891247x-foo.txt" "hello!" ]
|
|||
|
|
|||
|
# Außerdem können wir Dateien in den Nix Store downloaden.
|
|||
|
(fetchurl "https://example.com/package-1.2.3.tgz")
|
|||
|
#=> "/nix/store/2drvlh8r57f19s9il42zg89rdr33m2rm-package-1.2.3.tgz"
|
|||
|
|
|||
|
]
|
|||
|
```
|
|||
|
|
|||
|
### Weitere Resourcen
|
|||
|
|
|||
|
* [Nix Manual - Nix expression language]
|
|||
|
(https://nixos.org/nix/manual/#ch-expression-language)
|
|||
|
|
|||
|
* [James Fisher - Nix by example - Part 1: The Nix expression language]
|
|||
|
(https://medium.com/@MrJamesFisher/nix-by-example-a0063a1a4c55)
|
|||
|
|
|||
|
* [Susan Potter - Nix Cookbook - Nix By Example]
|
|||
|
(http://funops.co/nix-cookbook/nix-by-example/)
|