EMZETT.
Login

Kurz: mutable struct Konto # veränderlich inhaber::String stand::Float64 end

Teil des Kurses Julia

Kapitel 5 von 8 im Kurs Julia. Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.

Structs: eigene Typen

struct Punkt                    # unveränderlich (immutable)
    x::Float64
    y::Float64
end
 
mutable struct Konto            # veränderlich
    inhaber::String
    stand::Float64
end
 
abstract type Form end
struct Kreis <: Form; r::Float64 end
struct Rechteck <: Form; b::Float64; h::Float64 end
 
flaeche(k::Kreis) = π * k.r^2
flaeche(r::Rechteck) = r.b * r.h
umfang(k::Kreis) = 2π * k.r
umfang(r::Rechteck) = 2 * (r.b + r.h)
 
p = Punkt(3, 4)
println(p, " ", p.x, " ", typeof(p), " ", fieldnames(Punkt))
k = Konto("Mia", 100.0)
k.stand += 50
println(k.inhaber, " ", k.stand, " ", ismutable(k), " ", ismutable(p))
 
formen = [Kreis(1.0), Rechteck(3.0, 4.0), Kreis(2.5)]
for f in formen
    println(typeof(f), ": Fläche ", round(flaeche(f), digits = 2), ", Umfang ", round(umfang(f), digits = 2))
end
println(sum(flaeche, formen) |> x -> round(x, digits = 3))
println(sort(formen, by = flaeche) .|> typeof)
 
# Konstruktoren mit Prüfung und Standardwerten
struct Person
    name::String
    alter::Int
    function Person(name, alter)
        alter < 0 && throw(ArgumentError("Alter darf nicht negativ sein"))
        new(name, alter)
    end
end
Person(name) = Person(name, 18)
println(Person("Tom"), " ", Person("Zoe", 31).alter)
try
    Person("Ben", -5)
catch e
    println(typeof(e), ": ", e.msg)
end
 
# Parametrische Typen
struct Paar{A, B}
    erstes::A
    zweites::B
end
println(Paar(1, "eins"), " ", typeof(Paar(1.5, :x)))
using Printf
Base.show(io::IO, p::Punkt) = @printf(io, "Punkt(%.1f, %.1f)", p.x, p.y)
println(p, " ", [Punkt(1, 2), Punkt(3, 4)])

Ausgabe:

Punkt(3.0, 4.0) 3.0 Punkt (:x, :y)
Mia 150.0 true false
Kreis: Fläche 3.14, Umfang 6.28
Rechteck: Fläche 12.0, Umfang 14.0
Kreis: Fläche 19.63, Umfang 15.71
34.777
DataType[Kreis, Rechteck, Kreis]
Person("Tom", 18) 31
ArgumentError: Alter darf nicht negativ sein
Paar{Int64, String}(1, "eins") Paar{Float64, Symbol}
Punkt(3.0, 4.0) Punkt[Punkt(1.0, 2.0), Punkt(3.0, 4.0)]

Julia hat keine Klassen mit Methoden im Objekt: Daten (struct) und Verhalten (Funktionen mit Mehrfachverteilung) sind getrennt. Vererbung gibt es nur für abstrakte Typen (Hierarchie), nicht für Felder; für Wiederverwendung nutzt man Komposition.

Fehlerbehandlung

function teile(a, b)
    b == 0 && throw(DivideError())
    return a / b
end
 
try
    println(teile(10, 2))
    println(teile(1, 0))
catch e
    println("Fehler: ", typeof(e))
finally
    println("finally")
end
 
function lies_zahl(s)
    try
        return parse(Int, s)
    catch e
        e isa ArgumentError || rethrow()
        return nothing
    end
end
println(lies_zahl("42"), " ", lies_zahl("x"))
 
struct MeinFehler <: Exception
    code::Int
    text::String
end
Base.showerror(io::IO, e::MeinFehler) = print(io, "MeinFehler $(e.code): $(e.text)")
try
    throw(MeinFehler(404, "nicht gefunden"))
catch e
    println(sprint(showerror, e), " | ", e.code)
end
 
x = tryparse(Float64, "3.5")
println(x, " ", tryparse(Float64, "abc"), " ", something(tryparse(Int, "q"), -1))
@assert 1 + 1 == 2 "Mathe kaputt"
println(isa(try error("boom") catch e e end, ErrorException))
println(try [1, 2, 3][5] catch e typeof(e) end)
println(try sqrt(-1) catch e typeof(e) end)
println(try Int("x") catch e typeof(e) end)
println(try undefined_variable catch e typeof(e) end)
println(try 1 + "a" catch e typeof(e) end)

Ausgabe:

5.0
Fehler: DivideError
finally
42 nothing
MeinFehler 404: nicht gefunden | 404
3.5 nothing -1
true
BoundsError
DomainError
MethodError
UndefVarError
MethodError

Module und Pakete

Ein Modul ist ein eigener Namensraum. Pakete laden mit using (alle exportierten Namen) oder import (nur Modulnamen):

module Geometrie
export kreisflaeche, PI2
 
const PI2 = 2π
 
kreisflaeche(r) = π * r^2
hilfsfunktion(x) = x + 1          # nicht exportiert
 
end
 
using .Geometrie                 # lokales Modul: mit Punkt
println(kreisflaeche(2.0) |> x -> round(x, digits = 3), " ", PI2 |> x -> round(x, digits = 3))
println(Geometrie.hilfsfunktion(1))
 
using Statistics, Random, Dates
println(mean([1, 2, 3, 4]), " ", median([3, 1, 2]), " ", std([2, 4, 4, 4, 5, 5, 7, 9]) |> x -> round(x, digits = 4), " ", var([1, 2, 3, 4]))
Random.seed!(42)
println(length(rand(5)), " ", all(0 .<= rand(100) .< 1), " ", randperm(5) |> sort)
println(Date(2025, 3, 15) + Day(20), " ", dayofweek(Date(2025, 3, 15)), " ", Date(2025, 12, 24) - Date(2025, 3, 15))

Ausgabe:

12.566 6.283
2
2.5 2.0 2.1381 1.6666666666666667
5 true [1, 2, 3, 4, 5]
2025-04-04 6 284 days

Weitere Standardbibliotheken: LinearAlgebra, Statistics, Random, Dates, Printf, Test, Distributed, SparseArrays, Downloads, Pkg.

Merke

  • struct (unveränderlich) und mutable struct; abstrakte Typen bilden Hierarchien
  • Verhalten steckt in Funktionen mit Mehrfachverteilung, nicht im Objekt
  • Eigene Konstruktoren mit new(...), parametrische Typen Paar{A, B}
  • try/catch/finally, throw, rethrow(), tryparse
  • Module: module ... end, export, using, import

Übungsaufgabe

Definiere einen abstrakten Typ Tier mit zwei konkreten Typen und einer Funktion laut.

Quiz zur Selbstkontrolle

Weiter im Kurs

Zurück: Arrays, Tupel, Dicts und Mengen

Weiter: Leistung, Numerik und Parallelität

Alle Kapitel: Julia im Überblick