Lade den Code herunter: learncrystal.cr
# Das ist ein Kommentar
# Alles ist ein Objekt
nil.class # => Nil
100.class # => Int32
true.class # => Bool
# Falschwerte sind: nil, false und Nullpointer
!nil # => true : Bool
!false # => true : Bool
!0 # => false : Bool
# Integer
1.class # => Int32
# Fünf vorzeichenbehaftete Ganzzahlen
1_i8.class # => Int8
1_i16.class # => Int16
1_i32.class # => Int32
1_i64.class # => Int64
1_i128.class # => Int128
# Fünf vorzeichenlose Ganzzahlen
1_u8.class # => UInt8
1_u16.class # => UInt16
1_u32.class # => UInt32
1_u64.class # => UInt64
1_u128.class # => UInt128
2147483648.class # => Int64
9223372036854775808.class # => UInt64
# Binäre Zahlen
0b1101 # => 13 : Int32
# Oktalzahlen
0o123 # => 83 : Int32
# Hexadezimalzahlen
0xFE012D # => 16646445 : Int32
0xfe012d # => 16646445 : Int32
# Gleitkommazahlen (floats)
1.0.class # => Float64
# Es gibt zwei Typen von Gleitkommazahlen
1.0_f32.class # => Float32
1_f32.class # => Float32
1e10.class # => Float64
1.5e10.class # => Float64
1.5e-7.class # => Float64
# Chars (einzelne Zeichen)
'a'.class # => Char
# Oktale Schreibweise
'\101' # => 'A' : Char
# Unicode Schreibweise
'\u0041' # => 'A' : Char
# Strings (Zeichenketten)
"s".class # => String
# Strings sind unveränderlich
s = "hello, " # => "hello, " : String
s.object_id # => 1234667712 : UInt64
s += "Crystal" # => "hello, Crystal" : String
s.object_id # => 142528472 : UInt64
# Interpolation wird unterstützt
"sum = #{1 + 2}" # => "sum = 3" : String
# Mehrzeilige Strings
" Dies ist ein
mehrzeiliger String."
# String mit doppeltem Anführungszeichen
%(hello "world") # => "hello \"world\""
# Symbole
# Unveränderbare, wiederverwendbare Konstanten, welche intern als Int32 Integer
# Werte repräsentiert werden.
# Symbole werden oft anstelle von Strings verwendet, um bestimmte Werte zu bestimmen.
:symbol.class # => Symbol
sentence = :question? # :"question?" : Symbol
sentence = :question? # => true : Bool
sentence = :exclamation! # => false : Bool
sentence = "question?" # => false : Bool
# Arrays
[1, 2, 3].class # => Array(Int32)
[1, "hello", 'x'].class # => Array(Int32 | String | Char)
# Leere Arrays sollten einen Typen definieren
[] # => Syntaxfehler: für leere Arrays,
# verwende `[] of ElementType`
[] of Int32 # => [] : Array(Int32)
Array(Int32).new # => [] : Array(Int32)
# Arrays können indiziert werden
array = [1, 2, 3, 4, 5] # => [1, 2, 3, 4, 5] : Array(Int32)
array[0] # => 1 : Int32
array[10] # führt zu einem IndexError
array[-6] # führt zu einem IndexError
array[10]? # => nil : (Int32 | Nil)
array[-6]? # => nil : (Int32 | Nil)
# Starte am Ende des Arrays
array[-1] # => 5
# Mit einem Startindex und einer Länge
array[2, 4] # => [3, 4, 5]
# oder mit einem Bereich
array[1..3] # => [2, 3, 4]
# Füge etwas zu einem Array hinzu
array << 6 # => [1, 2, 3, 4, 5, 6]
# Entferne Einträge am Ende des Arrays
array.pop # => 6
array # => [1, 2, 3, 4, 5]
# Entferne ersten Eintrag im Array
array.shift # => 1
array # => [2, 3, 4, 5]
# Überprüfe, ob ein Element in einem Array existiert
array.includes? 3 # => true
# Spezielle Syntax für String-Arrays und Symbol-Arrays
%w(one two three) # => ["one", "two", "three"] : Array(String)
%i(one two three) # 0> [:one, :two, :three] : Array(Symbol)
# Es gibt auch für andere Arrays eine spezielle Syntax, wenn die Methoden
# `.new` und `#<<` definiert werden.
set = Set{1, 2, 3} # => [1, 2, 3]
set.class # => Set(Int32)
# Das obere ist äquivalent zu:
set = Set(typeof(1, 2, 3)).new
set << 1
set << 2
set << 3
# Hashes
{1 => 2, 3 => 4}.class # => Hash(Int32, Int32)
{1 => 2, 'a' => 3}.class # => Hash (Int32 | Char, Int32)
# Leere Hashes sollten einen Typen spezifizieren
{} # Syntaxfehler
{} of Int32 => Int32 # {}
Hash(Int32, Int32).new # {}
# Hashes können schnell mit dem Key nachgeschaut werden
hash = {"color" => "green", "number" => 5}
hash["color"] # => "green"
hash["no_such_key"] # => Fehlender hash key: "no_such_key" (KeyError)
hash["no_such_key"]? # => nil
# Überprüfe die Existenz eines Hashkeys
hash.has_key? "color" # => true
# Spezielle Schreibweise für Symbol- und Stringkeys
{key1: 'a', key2: 'b'} # {:key1 => 'a', :key2 => 'b'}
{"key1": 'a', "key2": 'b'} # {"key1" => 'a', "key2" => 'b'}
# Die spezielle Syntax für Hash-Literale gibt es auch für andere Typen, sofern
# diese die Methoden `.new` und `#[]=` Methoden definieren.
class MyType
def []=(key, value)
puts "do stuff"
end
end
MyType{"foo" => "bar"}
# Das obere ist äquivalent zu:
tmp = MyType.new
tmp["foo"] = "bar"
tmp
# Ranges (Bereiche)
1..10 # => Range(Int32, Int32)
Range.new(1,10).class # => Range(Int32, Int32)
# Ranges können inklusiv oder exklusiv sein.
(3..5).to_a # => [3, 4, 5]
(3...5).to_a # => [3, 4]
# Überprüfe, ob ein Range einen Wert enthält oder nicht.
(1..8).includes? 2 # => true
# Tupel sind unveränderliche, Stack-zugewiese Folgen von Werten mit fester
# Größe und möglicherweise unterschiedlichen Typen
{1, "hello", 'x'}.class # => Tuple(Int32, String, Char)
# Erhalte den Wert eines Tupels über den Index
tuple = {:key1, :key2}
tuple[1] # => :key2
tuple[2] # syntax error: Index out of bound
# Können auf mehrere Variablen erweitert werden
a, b, c = {:a, 'b', "c"}
a # => :a
b # => 'b'
c # => "c"
# Procs repräsentieren ein Funktionspointer mit einem optionalen Kontext.
# Normalerweise wird ein Proc mit einem proc-Literal erstellt.
proc = ->(x : Int32) { x.to_s }
proc.class # => Print(Int32, String)
# Außerdem kann man auch mit der Methode `new` ein Proc erstellen.
Proc(Int32, String).new { |x| x.to_s }
# Rufe ein Proc auf mit der Methode `call`
proc.call 10 # => "10"
# Kontrollstatements
if true
"if statement"
elsif false
"else-f, optional"
else
"else, auch optional"
end
puts "if as a suffix" if true # => if as a suffix
# If als Ausdruck
a = if 2 > 1
3
else
4
end
a # => 3
# Bedingter ternärer Ausdruck
a = 1 > 2 ? 3 : 4 # => 4
# Case-Statement
cmd = "move"
action = case cmd
when "create"
"Creating..."
when "copy"
"Copying..."
when "move"
"Moving..."
when "delete"
"Deleting..."
end
action # => "Moving..."
# Schleifen
index = 0
while index <= 3
puts "Index: #{index}"
index += 1
end
# Index: 0
# Index: 1
# Index: 2
# Index: 3
index = 0
until index > 3
puts "Index: #{index}"
index += 1
end
# Index: 0
# Index: 1
# Index: 2
# Index: 3
# Der bevorzugte Weg, ist `each` zu verwenden.
(1..3).each do |index|
puts "Index: #{index}"
end
# Index: 1
# Index: 2
# Index: 3
# Der Typ der Variablen hängt vom Typen innerhalb der Kontrollanweisung ab
if a < 3
a = "hello"
else
a = true
end
typeof a # => (Bool | String)
if a && b
# Hier wird garantiert, dass weder a noch b vom Typ Nil sind
end
if a.is_a? String
a.class # => String
end
# Funktionen
def double(x)
x * 2
end
# Funktionen geben implizit den Wert der letzten Anweisung zurück
# Dies ist auch bei anderen Blöcken der Fall.
double(2) # => 4
# Klammern müssen nicht gesetzt werden, wenn der Aufruf eindeutig ist
double 3 # => 6
double double 3 # => 12
def sum(x, y)
x + y
end
# Funktionsargumente werden mit einem Komma separiert.
sum 3, 4 # => 7
sum sum(3, 4), 5 # => 12
# yield
# Alle Methoden haben einen impliziten, optionalen Blockparameter.
# Dieser kann mit dem Schlüsselwort `yield` aufgerufen werden.
def surround
puts '{'
yield
puts '}'
end
surround { puts "Hallo Welt" }
# {
# Hallo Welt
# }
# Du kannst ein Block einer Funktion übergeben.
# "&" kennzeichnet eine Referenz zu einem übergebenen Block
def guests(&block)
block.call "some_argument"
end
# Du kannst eine Liste von Argumenten mitgeben, welche zu einem Array
# umgewandelt werden.
# Hierfür ist der Splat-Operator ("*")
def guests(*array)
array.each { |guest| puts guest }
end
# Wenn eine Methode ein Array zurückgibt, kann destrukturiende Zuordnung
# verwendet werden.
def foods
["pancake", "sandwich", "quesadilla"]
end
breakfast, lunch, dinner = foods
breakfast # => "pancake"
dinner # => "quesadilla"
# Gemäß der Konvention enden alle Methoden, welchen einen Boolean zurückgeben
# mit einem Fragezeichen.
5.even? # false
5.odd? # true
# Und wenn eine Methode mit einem Ausrufezeichen endet, macht sie etwas
# destruktives. Zum Beispiel wird der Aufrufer verändert. Einige Methoden haben
# eine !-Version, um eine Änderung zu machen und eine Nicht-!-Version, welche
# lediglich eine neue veränderte Version zurückgibt.
company_name = "Dunder Mifflin"
company_name.gsub "Dunder", "Donald" # => "Donald Mifflin"
company_name # => "Dunder Mifflin"
company_name.gsub! "Dunder", "Donald"
company_name # => "Donald Mifflin"
# definiere eine Klasse mit dem Schlüsselwort `class`.
class Human
# eine Klassenvariable. Diese wird mit allen Instanzen dieser Klasse geteilt.
@@species = "H. sapiens"
# type of name is String
@name: String
# Grundlegender Intialisierer
# Weise das Argument der Instanz-Variable "name" zu
# Wenn kein Alter angegeben wird, wird der Default (hier 0) genommen.
def initialize(@name, @age = 0)
end
# Einfache Setter-Methode
def name=(name)
@name = name
end
# einfache Getter-Methode
def name
@name
end
# Die obere Funktionalität kann mit der property-Methode gekapselt werden:
property :name
# Getter/Setter-Methoden können auch individuell erstellt werden:
getter :name
setter :name
# eine Klassenmethode verwendet `self` um sich von Instanzmethoden zu
# unterscheiden. Diese kann lediglich von einer Klasse aufgerufen werden,
# nicht von einer Instanz.
def self.say(msg)
puts msg
end
def species
@@species
end
end
# Eine Klasse instanziieren
jim = Human.new("Jim Halpert")
dwight = Human.new("Dwight K. Schrute")
# Lass uns ein paar Methoden aufrufen
jim.species # => "H. sapiens"
jim.name # => "Jim Halpert"
jim.name = "Jim Halpert II" # => "Jim Halpert II"
jim.name # => "Jim Halpert II"
dwight.species # => "H. sapiens"
dwight.name # => "Dwight K. Schrute"
# Rufe die Klassenmethode auf
Human.say("Hi") # => gibt Hi aus und gibt `nil` zurück
# Variablen, welche mit @ starten, sind im Scope der Instanz
class TestClass
@var = "Ich bin eine Instanzvariable"
end
# Variablen, welche mit @@ starten, sind im Scope der Klasse
class TestClass
@@var = "Ich bin eine Klassenvariable"
end
# Variablen, welche mit einem Großbuchstaben starten, sind Konstanten.
Var = "Ich bin eine Konstante"
Var = "Ich kann nicht aktualisiert werden." # Die Konstante Var wurde bereits
# initialisiert.
# In Crystal ist Class auch ein Objekt. Dadurch können Klassen Instanzvariablen
# haben. Klassenvariablen werden mit der Klasse und allen Subklassen geteilt.
# Basisklasse
class Human
@@foo = 0
def self.foo
@@foo
end
def self.foo=(value)
@@foo = value
end
end
# abgeleitete Klasse
class Worker < Human
end
Human.foo # => 0
Worker.foo # => 0
Human.foo = 2 # => 2
Worker.foo # => 0
Worker.foo = 3 # => 3
Human.foo # => 2
Worker.foo # => 3
module ModuleExample
def foo
"foo"
end
end
# Wenn ein Modul mit include eingeschlossen wird, so werden die Methoden an die
# Instanzen gebunden.
# Wenn eine Klasse mit einem Modul erweitert wird, so werden die Methoden an die
# Klasse selbst gebunden.
class Person
include ModuleExample
end
class Book
extend ModuleExample
end
Person.foo # => undefinierte Methode 'foo' für Person:Class
Person.new.foo # => 'foo'
Book.foo # => 'foo'
Book.new.foo # => undefinierte Methode für Book
# Ausnahmebehandlung
# Definiere eine neue Ausnahme
class MyException < Exception
end
# Definiere eine weitere Ausnahme
class MyAnotherException < Exception; end
ex = begin
raise MyException.new
rescue ex1 : IndexError
"ex1"
rescue ex2 : MyException | MyAnotherException
"ex2"
rescue ex3 : Exception
"ex3"
rescue ex4 # fange alle Ausnahmen ab
"ex4"
end
ex # => "ex2"
Du hast einen Verbesserungsvorschlag oder einen Fehler gefunden? Erstelle ein Ticket im offiziellen GitHub Repo, oder du erstellst einfach gleich einen pull request!
Originalversion von Vitalii Elenhaupt, mit Updates von 3 contributors.