log = 3
1 + log4
_ und das Ausrufezeichen ! enthalten.Nmax und NMAX sind verschiedene Variablen.if, then, function, true, false,...zulässig: i, x, Ω, x2, DieUnbekannteZahl, neuer_Wert, 🎷, Zähler, лічильник, einself!!!!,...
unzulässig: Uwe's_Funktion, 3achsen, A#B, $this_is_not_Perl, true,...
Neben den reserved keywords der Kernsprache sind zahlreiche weitere Funktionen und Objekte vordefiniert, wie z.B. die mathematischen Funktionen sqrt(), log(), sin(). Diese Definitionen finden sich in dem Modul Base, welches Julia beim Start automatisch lädt. Namen aus Base können umdefiniert werden, solange sie noch nicht verwendet wurden:
log = 3
1 + log4
Jetzt ist natürlich der Logarithmus kaputt:
x = log(10)MethodError: objects of type Int64 are not callable
The object of type `Int64` exists, but no method is defined for this combination of argument types when trying to treat it as a callable object.
Maybe you forgot to use an operator such as *, ^, %, / etc. ?
Stacktrace:
[1] top-level scope
@ ~/Julia/23/Book-ansipatch/chapters/syntax.qmd:47
(siehe auch https://stackoverflow.com/questions/65902105/how-to-reset-any-function-in-julia-to-its-original-state)
Im interaktiven Betrieb wird der Wert der letzten Anweisung auch ohne explizites print() ausgegeben:
println("Hallo 🌍!")
x = sum([i^2 for i=1:10])Hallo 🌍!
385
Das Semikolon unterdrückt das:
println("Hallo 🌍!")
x = sum([i^2 for i=1:10]);Hallo 🌍!
Bei mehrzeiligen Anweisungen muss die fortzusetzende Zeile mit einer offenen Operation oder Klammer enden:
x = sin(π/2) +
3 * cos(0)4.0
Also geht das Folgende schief, aber leider ohne eine Fehlermeldung!
x = sin(π/2)
+ 3 * cos(0)
println(x)1.0
Hier wird das + in der zweiten Zeile als Präfix-Operator (Vorzeichen) interpretiert. Damit sind 1. und 2. Zeile jeweils für sich vollständige, korrekte Ausdrücke (auch wenn die 2. Zeile natürlich völlig nutzlos ist) und werden auch so abgearbeitet.
Moral: Wenn man längere Ausdrücke auf mehrere Zeilen aufteilen will, sollte man immer eine Klammer aufmachen. Dann ist egal, wo der Zeilenumbruch ist:
x = ( sin(π/2)
+ 3 * cos(0) )
println(x)4.0
Julia kennt 2 Arten von Kommentaren im Programmtext:
# Einzeilige Kommentare beginnen mit einem Doppelkreuz.
x = 2 # alles vom '#' bis zum Zeilenende ist ein Kommentar und wird ignoriert. x = 32
#=
Ein- und mehrzeilige Kommentare können zwischen #= ... =# eingeschlossen werden.
Dabei sind verschachtelte Kommentare möglich.
#=
d.h., anders als in C/C++/Java endet der Kommentar nicht mit dem ersten
Kommentar-Endezeichen, sondern die #=...=# - Paare wirken wie Klammern.
=#
Der automatische 'syntax highlighter' weiss das leider noch nicht, wie die wechselnde
Graufärbung dieses Kommentars zeigt.
=#
x #= das ist ein seltener Variablenname! =# = 33
x = ... an Objekte gebunden werden können.Einfache Basistypen sind z.B.:
Int64, Float64, String, Char, Bool
x = 2
x, typeof(x), sizeof(x)(2, Int64, 8)
x = 0.2
x, typeof(x), sizeof(x)(0.2, Float64, 8)
x = "Hallo!"
x, typeof(x), sizeof(x)("Hallo!", String, 6)
x = 'Ω'
x, typeof(x), sizeof(x)('Ω', Char, 4)
x = 3 > π
x, typeof(x), sizeof(x)(false, Bool, 1)
sizeof() liefert die Größe eines Objekts oder Typs in Bytes (1 Byte = 8 Bit)'A' und Zeichenketten/strings "A" der Länge 1 sind verschiedene Objekte.if-Blöckeif-Block kann beliebig viele elseif-Zweige und als letztes maximal einen else-Zweig enthalten.x = 33
y = 44
z = 34
if x < y && z != x # elseif- und else-Blöcke sind optional
println("yes")
x += 10
elseif x < z # beliebig viele elseif-Blöcke
println(" x is smaller than z")
elseif x == z+1
println(" x is successor of z")
else # maximal ein else-Block
println("Alles falsch")
end # Wert des gesamten Blocks ist der Wert der
# letzten ausgeführten Auswertungyes
43
Kurze Blöcke kann man in eine Zeile schreiben:
if x > 10 println("x is larger than 10") endx is larger than 10
Der Wert eines if-Blocks kann natürlich zugewiesen werden:
y = 33
z = if y > 10
println("y is larger than 10")
y += 1
end
zy is larger than 10
34
test ? exp1 : exp2x = 20
y = 15
z = x < y ? x+1 : y+116
ist äquivalent zu
z = if x < y
x+1
else
y+1
end16
==!=, ≠>>=, ≥<<=, ≤Wie üblich, ist der Test auf Gleichheit == vom Zuweisungsoperator = zu unterscheiden. Vergleichen lässt sich so gut wie alles:
"Aachen" < "Leipzig", 10 ≤ 10.01, [3,4,5] < [3,6,2](true, true, true)
Nun ja, fast alles:
3 < "vier"MethodError: no method matching isless(::Int64, ::String)
The function `isless` exists, but no method is defined for this combination of argument types.
Closest candidates are:
isless(::Missing, ::Any)
@ Base missing.jl:87
isless(::Any, ::Missing)
@ Base missing.jl:88
isless(::AbstractString, ::AbstractString)
@ Base strings/basic.jl:359
...
Stacktrace:
[1] <(x::Int64, y::String)
@ Base ./operators.jl:353
[2] top-level scope
@ ~/Julia/23/Book-ansipatch/chapters/syntax.qmd:260
Die Fehlermeldung zeigt ein paar Grundprinzipien von Julia:
x < y wird zum Funktionsaufruf isless(x, y).Man kann sich alle Methoden zu einer Funktion anzeigen lassen. Das gibt einen Einblick in das komplexe Typssystem von Julia:
methods(<)Zuletzt noch: Vergleiche können gekettet werden.
10 < x ≤ 100 # das ist äquivalent zu
# 10 < x && x ≤ 100true
Einge Funktionen vom Typ f(c::Char) -> Bool
isnumeric('a'), isnumeric('7'), isletter('a')(false, true, true)
und vom Typ f(s1::String, s2::String) -> Bool
contains("Lampenschirm", "pensch"), startswith("Lampenschirm", "Lamb"), endswith("Lampenschirm", "rm")(true, false, true)
in(item, collection) -> Bool testet, ob item in collection ist.∈(item, collection) undin als auch ∈ können auch als Infix-Operatoren geschrieben werden.x = 3
x in [1, 2, 3, 4, 5]true
x ∈ [1, 2, 33, 4, 5]false
&&, ||, !3 < 4 && !(2 > 8) && !contains("aaa", "b")true
a && b wird b nur ausgewertet, wenn a == truea || b wird b nur ausgewertet, wenn a == falseDamit kann if test statement end auch als test && statement geschrieben werden.
Damit kann if !test statement end als test || statement geschrieben werden.
Als Beispiel1 hier eine Implementierung der Fakultätsfunktion (factorial):
function fact(n::Int)
n >= 0 || error("n must be non-negative")
n == 0 && return 1
n * fact(n-1)
end
fact(5)120
Natürlich kann man alle diese Tests auch Variablen vom Typ Bool zuordnen und diese Variablen können als Tests in if- und while-Blöcken verwendet werden:
x = 3 < 4
y = 5 ∈ [1, 2, 5, 7]
z = x && y
if z # äquivalent zu: if 3 < 4 && 5 in [1,2,5,7]
println("Stimmt alles!")
endStimmt alles!
Bool sein.x ein numerischer Typ ist, dann muss daher das C-Idiom if(x) als if x != 0 geschrieben werden.a && b && c... bzw a || b || c... muss der letzte Teilausdruck nicht vom Typ Bool sein, wenn diese Konstrukte nicht als Tests in if oder while verwendet werden:z = 3 < 4 && 10 < 5 && sqrt(3^3)
z, typeof(z)(false, Bool)
z = 3 < 4 && 10 < 50 && sqrt(3^3)
z, typeof(z)(5.196152422706632, Float64)
while (“solange”)-SchleifeSyntax:
while *condition*
*loop body*
end
Eine Reihe von Anweisungen (der Schleifenkörper) wird immer wieder abgearbeitet, solange eine Bedingung erfüllt ist.
i = 1 # typischerweise braucht der Test der
# while-Schleife eine Vorbereitung ...
while i < 10
println(i)
i += 2 # ... und ein update
end1
3
5
7
9
Der Körper einer while- und for-Schleife kann die Anweisungen break und continue enthalten. break stoppt die Schleife, continue überspringt den Rest des Schleifenkörpers und beginnt sofort mit dem nächsten Schleifendurchlauf.
i = 0
while i<10
i += 1
if i == 3
continue # beginne sofort nächsten Durchlauf,
end # überspringe Rest des Schleifenkörpers
println("i = $i")
if i ≥ 5
break # breche Schleife ab
end
end
println("Fertig!")i = 1
i = 2
i = 4
i = 5
Fertig!
Mit break kann man auch Endlosschleifen verlassen:
i = 1
while true
println(2^i)
i += 1
if i > 8 break end
end2
4
8
16
32
64
128
256
for-SchleifenSyntax:
for *var* in *iterable container*
*loop body*
end
Der Schleifenkörper wird für alle Items aus einem Container durchlaufen.
Statt in kann immer auch \(\in\) verwendet werden. Im Kopf einer for-Schleife kann auch = verwendet werden.
for i ∈ ["Mutter", "Vater", "Tochter"]
println(i)
endMutter
Vater
Tochter
Oft benötigt man einen numerischen Schleifenzähler. Dafür gibt es das range-Konstrukt. Die einfachsten Formen sind Start:Ende und Start:Schrittweite:Ende.
endwert = 5
for i ∈ 1:endwert
println(i^2)
end1
4
9
16
25
for i = 1:5.5 print(" $i") end 1.0 2.0 3.0 4.0 5.0
for i = 1:2:14 print(" $i") end 1 3 5 7 9 11 13
for k = 14 : -2.5 : 1 print(" $k") end 14.0 11.5 9.0 6.5 4.0 1.5
Ein break beendet die innerste Schleife.
for i = 1:3
for j = 1:3
println( (i,j) )
if j == 2
break
end
end
end(1, 1)
(1, 2)
(2, 1)
(2, 2)
(3, 1)
(3, 2)
Man kann nested loops auch in einer for-Anweisung zusammenfassen. Dann beendet ein break die Gesamtschleife.
for i = 1:3, j=1:3 # im Prinzip dasselbe wie oben, aber:
println( (i,j) )
if j == 2
break # break bricht hier die Gesamtschleife ab
end
end(1, 1)
(1, 2)
for-Schleifen!
Bei jedem Schleifendurchlauf wird die Laufvariable neu mit dem nächsten Element aus dem Container initialisiert.
for i = 1:5
print(i," ... ")
i += 2
println(i)
end1 ... 3
2 ... 4
3 ... 5
4 ... 6
5 ... 7
Die C-Semantik von for(i=1; i<5; i++) entspricht der while-Schleife:
i = 1
while i<5
*loop body* # hier kann auch wirksam an i rumgepfuscht werden
i += 1
end
Julia verwendet Unicode als Zeichensatz. Damit können für Variablen, Funktionen etc auch Bezeichner aus nicht-lateinischen Schriften (zB Kyrillisch, Koreanisch, Sanskrit, Runen, Emoji,…) verwendet werden. Die Frage, wie man solche Zeichen in seinem Editor eingeben kann und ob der verwendete Bildschirm-Font sie darstellen kann, ist nicht Julias Problem.
Einige Unicode-Zeichen, z.B. ≤, ≠, ≥, π, ∈, √, können anstelle von <=, !=, >=, pi, in, sqrt verwendet werden.
über 3000 Unicode-Zeichen können in Julia in einer LaTeX-ähnlichen Weise mit der Tab-Vervollständigung eingegeben werden.
\alpha<TAB> wird zu α,\euler<TAB> wird zu ℯ (Eulersche Zahl exp(1), spezielles Schreibschrift-e, U+0212F)\le<TAB> wird zu ≤,\in<TAB> wird zu ∈,\:rainbow:<TAB> wird zu 🌈Man kann den Multiplikationsoperator * nach einer numerischen Konstanten weglassen, wenn eine Variable, Funktion oder öffnende Klammer folgt.
z = 3.4x + 2(x+y) + xyist daher korrektes Julia. Beachte allerdings, dass der Term xy als eine Variable mit dem Namen xy interpretiert wird und nicht als Produkt von x und y!
Das funktioniert wie erwartet:
e = 7
3e21
Hier wird die Eingabe als Gleitkommazahl interpretiert – und 3E+2 oder 3f+2 (Float32) ebenso.
3e+2300.0
Ein Leerzeichen schafft Eindeutigkeit:
3e + 223
Das funktioniert:
x = 4
3x + 315
…und das nicht. 0x, 0o, 0b wird als Anfang einer Hexadezimal-, Oktal- bzw. Binärkonstanten interpretiert.
3y + 0xParseError:
# Error @ /home/hellmund/Julia/23/Book-ansipatch/chapters/syntax.qmd:579:6
3y + 0x
# └┘ ── invalid numeric constant
Stacktrace:
[1] top-level scope
@ ~/Julia/23/Book-ansipatch/chapters/syntax.qmd:579
Wichtig = 21
Wichtig! = 42 # Bezeichner können auch ein ! enthalten
(Wichtig, Wichtig!)(21, 42)
Wichtig!=88true
Julia interpretiert das als Vergleich Wichtig != 88.
Leerzeichen helfen:
Wichtig! = 88
Wichtig!88
.*, .+,… haben in Julia eine spezielle Bedeutung (broadcasting, d.h., vektorisierte Operationen).1.+2.ParseError:
# Error @ /home/hellmund/Julia/23/Book-ansipatch/chapters/syntax.qmd:612:1
1.+2.
└┘ ── ambiguous `.` syntax; add whitespace to clarify (eg `1.+2` might be `1.0+2` or `1 .+ 2`)
Stacktrace:
[1] top-level scope
@ ~/Julia/23/Book-ansipatch/chapters/syntax.qmd:612
Wieder gilt: Leerzeichen schaffen Klarheit!
1. + 2.3.0
aus der Julia-Dokumentation↩︎