Kurz: @@anzahl = 0 # Klassenvariable ZINS = 0.02 # Konstante
Teil des Kurses Ruby
Klassen
class Konto
attr_reader :inhaber, :stand # Getter
attr_accessor :notiz # Getter + Setter
@@anzahl = 0 # Klassenvariable
ZINS = 0.02 # Konstante
def initialize(inhaber, stand = 0) # Konstruktor
@inhaber = inhaber # Instanzvariablen beginnen mit @
@stand = stand
@@anzahl += 1
end
def einzahlen(betrag)
raise ArgumentError, "Betrag muss positiv sein" unless betrag.positive?
@stand += betrag
self # für Verkettung
end
def reich? = @stand > 1000
def to_s = "#{@inhaber}: #{format('%.2f', @stand)}"
def self.anzahl = @@anzahl # Klassenmethode
private
def geheim = "intern"
end
k = Konto.new("Mia", 100)
k.einzahlen(50).einzahlen(25.5)
puts k
puts k.reich?
k.notiz = "VIP"
puts k.notiz
puts Konto.anzahl
puts Konto::ZINS
begin
k.einzahlen(-5)
rescue ArgumentError => e
puts "Fehler: #{e.message}"
end
begin
k.geheim
rescue NoMethodError => e
puts "NoMethodError: #{e.message[0, 40]}"
end
puts k.inspect.sub(/0x[0-9a-f]+/, "0x...")
puts k.instance_variables.inspect
puts k.respond_to?(:einzahlen), k.is_a?(Konto), Konto.instance_methods(false).sort.first(3).inspectAusgabe:
Mia: 175.50
false
VIP
1
0.02
Fehler: Betrag muss positiv sein
NoMethodError: private method `geheim' called for an in
#<Konto:0x... @inhaber="Mia", @stand=175.5, @notiz="VIP">
[:@inhaber, :@stand, :@notiz]
true
true
[:einzahlen, :inhaber, :notiz]Sichtbarkeit: public (Standard), protected (nur Objekte derselben Klasse), private (nur ohne expliziten Empfänger aufrufbar).
Vererbung
class Tier
attr_reader :name
def initialize(name) = @name = name
def laut = "..."
def vorstellen = "#{name} sagt #{laut}"
end
class Hund < Tier
def laut = "Wuff"
end
class Katze < Tier
def initialize(name, leben = 9)
super(name) # Elternkonstruktor
@leben = leben
end
def laut = "Miau"
def vorstellen = super + " (#{@leben} Leben)"
end
[Hund.new("Rex"), Katze.new("Mimi")].each { |t| puts t.vorstellen }
puts Hund.superclass, Hund.ancestors.first(3).inspect
puts Katze.new("x").is_a?(Tier), Hund.instance_method(:laut).ownerAusgabe:
Rex sagt Wuff
Mimi sagt Miau (9 Leben)
Tier
[Hund, Tier, Object]
true
HundRuby kennt nur Einfachvererbung, ergänzt durch Module (nächstes Kapitel).
Operatoren, Vergleich und Gleichheit
class Vektor
include Comparable
attr_reader :x, :y
def initialize(x, y) = (@x, @y = x, y)
def +(o) = Vektor.new(x + o.x, y + o.y)
def *(k) = Vektor.new(x * k, y * k)
def -@ = Vektor.new(-x, -y)
def [](i) = i.zero? ? x : y
def <=>(o) = laenge <=> o.laenge
def laenge = Math.sqrt(x**2 + y**2)
def ==(o) = o.is_a?(Vektor) && x == o.x && y == o.y
def to_s = "(#{x}, #{y})"
def inspect = "#<Vektor #{self}>"
def coerce(n) = [Vektor.new(n, n), self]
end
a = Vektor.new(1, 2)
b = Vektor.new(3, 4)
puts a + b, a * 3, -a, a[1]
puts a < b, [b, a].min, a == Vektor.new(1, 2), a.equal?(a)
puts a.between?(a, b), a.clamp(a, a)
p aAusgabe:
(4, 6)
(3, 6)
(-1, -2)
2
true
(1, 2)
true
true
true
(1, 2)
#<Vektor (1, 2)>Struct, Data und OpenStruct
Für einfache Datenträger gibt es Kurzformen:
Punkt = Struct.new(:x, :y) do
def abstand = Math.sqrt(x**2 + y**2)
end
p1 = Punkt.new(3, 4)
p p1, p1.abstand, p1.to_a, p1 == Punkt.new(3, 4)
p1.x = 10
puts p1.x
Koord = Data.define(:lat, :lon) do # unveränderlich (Ruby 3.2)
def to_s = "#{lat}/#{lon}"
end
k = Koord.new(lat: 52.5, lon: 13.4)
puts k, k.with(lat: 0).inspect
begin
k.instance_variable_set(:@lat, 1)
rescue FrozenError => e
puts "FrozenError"
end
case k
in { lat:, lon: } then puts "Muster: #{lat}"
endAusgabe:
#<struct Punkt x=3, y=4>
5.0
[3, 4]
true
10
52.5/13.4
#<data Koord lat=0, lon=13.4>
FrozenError
Muster: 52.5Merke
class Name ... end,initializeals Konstruktor,@variablenattr_reader/writer/accessorerzeugen Zugriffsmethodenprivate/protected, Klassenmethodenself.name- Vererbung
class B < A,super;Comparablefür Vergleiche StructundDatafür kleine Datenobjekte
Übungsaufgabe
Baue eine Klasse Rechteck mit flaeche, umfang und Vergleich über die Fläche (Comparable).
Quiz zur Selbstkontrolle
Was ist initialize?
- Der Konstruktor einer Klasse (richtig)
- Eine Klassenmethode
- Ein Modul
- Ein Destruktor
Was erzeugt attr_accessor :name?
- Getter und Setter für @name (richtig)
- Nur einen Getter
- Eine Konstante
- Eine Klassenvariable
Wie viele Elternklassen darf eine Ruby-Klasse haben?
- Eine (richtig)
- Beliebig viele
- Zwei
- Keine
Weiter im Kurs
Zurück: Methoden, Blöcke, Procs und Lambdas
Weiter: Module, Mixins und Enumerable
Alle Kapitel: Ruby im Überblick