= 3
log 1 + log
4
_
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:
= 3
log 1 + log
4
Jetzt ist natürlich der Logarithmus kaputt:
= log(10) x
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 🌍!")
= sum([i^2 for i=1:10]) x
Hallo 🌍!
385
Das Semikolon unterdrückt das:
println("Hallo 🌍!")
= sum([i^2 for i=1:10]); x
Hallo 🌍!
Bei mehrzeiligen Anweisungen muss die fortzusetzende Zeile mit einer offenen Operation oder Klammer enden:
= sin(π/2) +
x 3 * cos(0)
4.0
Also geht das Folgende schief, aber leider ohne eine Fehlermeldung!
= sin(π/2)
x + 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:
= ( sin(π/2)
x + 3 * cos(0) )
println(x)
4.0
Julia kennt 2 Arten von Kommentaren im Programmtext:
# Einzeilige Kommentare beginnen mit einem Doppelkreuz.
= 2 # alles vom '#' bis zum Zeilenende ist ein Kommentar und wird ignoriert. x = 3 x
2
#=
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.
=#
'syntax highlighter' weiss das leider noch nicht, wie die wechselnde
Der automatische
Graufärbung dieses Kommentars zeigt. =#
#= das ist ein seltener Variablenname! =# = 3 x
3
x = ...
an Objekte gebunden werden können.Einfache Basistypen sind z.B.:
Int64, Float64, String, Char, Bool
= 2
x typeof(x), sizeof(x) x,
(2, Int64, 8)
= 0.2
x typeof(x), sizeof(x) x,
(0.2, Float64, 8)
= "Hallo!"
x typeof(x), sizeof(x) x,
("Hallo!", String, 6)
= 'Ω'
x typeof(x), sizeof(x) x,
('Ω', Char, 4)
= 3 > π
x typeof(x), sizeof(x) 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.= 33
x = 44
y = 34
z
if x < y && z != x # elseif- und else-Blöcke sind optional
println("yes")
+= 10
x 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 Auswertung
yes
43
Kurze Blöcke kann man in eine Zeile schreiben:
if x > 10 println("x is larger than 10") end
x is larger than 10
Der Wert eines if
-Blocks kann natürlich zugewiesen werden:
= 33
y = if y > 10
z println("y is larger than 10")
+= 1
y end
z
y is larger than 10
34
test ? exp1 : exp2
= 20
x = 15
y = x < y ? x+1 : y+1 z
16
ist äquivalent zu
= if x < y
z +1
xelse
+1
yend
16
==
!=
, ≠
>
>=
, ≥
<
<=
, ≤
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 ≤ 100
true
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.= 3
x in [1, 2, 3, 4, 5] x
true
∈ [1, 2, 33, 4, 5] x
false
&&
, ||
, !
3 < 4 && !(2 > 8) && !contains("aaa", "b")
true
a && b
wird b
nur ausgewertet, wenn a == true
a || b
wird b
nur ausgewertet, wenn a == false
Damit 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)
>= 0 || error("n must be non-negative")
n == 0 && return 1
n * fact(n-1)
n 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:
= 3 < 4
x = 5 ∈ [1, 2, 5, 7]
y = x && y
z if z # äquivalent zu: if 3 < 4 && 5 in [1,2,5,7]
println("Stimmt alles!")
end
Stimmt 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:= 3 < 4 && 10 < 5 && sqrt(3^3)
z typeof(z) z,
(false, Bool)
= 3 < 4 && 10 < 50 && sqrt(3^3)
z typeof(z) 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.
= 1 # typischerweise braucht der Test der
i # while-Schleife eine Vorbereitung ...
while i < 10
println(i)
+= 2 # ... und ein update
i end
1
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.
= 0
i
while i<10
+= 1
i
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:
= 1
i
while true
println(2^i)
+= 1
i if i > 8 break end
end
2
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)
end
Mutter
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
.
= 5
endwert
for i ∈ 1:endwert
println(i^2)
end
1
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," ... ")
+= 2
i println(i)
end
1 ... 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) + xy
ist 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
3e
21
Hier wird die Eingabe als Gleitkommazahl interpretiert – und 3E+2
oder 3f+2
(Float32) ebenso.
3e+2
300.0
Ein Leerzeichen schafft Eindeutigkeit:
3e + 2
23
Das funktioniert:
= 4
x 3x + 3
15
…und das nicht. 0x
, 0o
, 0b
wird als Anfang einer Hexadezimal-, Oktal- bzw. Binärkonstanten interpretiert.
3y + 0x
ParseError:
# 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
= 21
Wichtig = 42 # Bezeichner können auch ein ! enthalten
Wichtig! (Wichtig, Wichtig!)
(21, 42)
!=88 Wichtig
true
Julia interpretiert das als Vergleich Wichtig != 88
.
Leerzeichen helfen:
= 88
Wichtig! 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↩︎