mirror of
https://github.com/adambard/learnxinyminutes-docs.git
synced 2024-12-23 15:24:09 +03:00
Merge pull request #1556 from coastalchief/master
Scala and Ruby article in german
This commit is contained in:
commit
a125b4a557
613
de-de/ruby-de.html.markdown
Normal file
613
de-de/ruby-de.html.markdown
Normal file
@ -0,0 +1,613 @@
|
||||
---
|
||||
language: ruby
|
||||
contributors:
|
||||
- ["David Underwood", "http://theflyingdeveloper.com"]
|
||||
- ["Joel Walden", "http://joelwalden.net"]
|
||||
- ["Luke Holder", "http://twitter.com/lukeholder"]
|
||||
- ["Tristan Hume", "http://thume.ca/"]
|
||||
- ["Nick LaMuro", "https://github.com/NickLaMuro"]
|
||||
- ["Marcos Brizeno", "http://www.about.me/marcosbrizeno"]
|
||||
- ["Ariel Krakowski", "http://www.learneroo.com"]
|
||||
- ["Dzianis Dashkevich", "https://github.com/dskecse"]
|
||||
- ["Levi Bostian", "https://github.com/levibostian"]
|
||||
- ["Rahil Momin", "https://github.com/iamrahil"]
|
||||
translators:
|
||||
- ["Christian Albrecht", "https://github.com/coastalchief"]
|
||||
filename: ruby-de.html.markdown
|
||||
lang: de-de
|
||||
---
|
||||
|
||||
# Dies ist ein Kommentar
|
||||
|
||||
=begin
|
||||
Dies sind multi-line
|
||||
Kommentare. Niemand benutzt
|
||||
die wirklich.
|
||||
=end
|
||||
|
||||
# Objekte - Alles ist ein Objekt
|
||||
|
||||
## Zahlen sind Objekte
|
||||
```
|
||||
3.class #=> Fixnum
|
||||
3.to_s #=> "3"
|
||||
```
|
||||
|
||||
### Simple Arithmetik
|
||||
```
|
||||
1 + 1 #=> 2
|
||||
8 - 1 #=> 7
|
||||
10 * 2 #=> 20
|
||||
35 / 5 #=> 7
|
||||
2**5 #=> 32
|
||||
```
|
||||
|
||||
// Arithmetik ist aber eigentlich nur syntaktischer Zucker
|
||||
// um eine Methode eines Objekt aufzurufen
|
||||
```
|
||||
1.+(3) #=> 4
|
||||
10.* 5 #=> 50
|
||||
```
|
||||
|
||||
## Special values sind Objekte
|
||||
```
|
||||
nil # Nothing to see here
|
||||
true # truth
|
||||
false # falsehood
|
||||
|
||||
nil.class #=> NilClass
|
||||
true.class #=> TrueClass
|
||||
false.class #=> FalseClass
|
||||
```
|
||||
|
||||
## Objektvergleiche
|
||||
### Gleicheit
|
||||
```
|
||||
1 == 1 #=> true
|
||||
2 == 1 #=> false
|
||||
```
|
||||
### Ungleichheit
|
||||
```
|
||||
1 != 1 #=> false
|
||||
2 != 1 #=> true
|
||||
```
|
||||
### Neben false selbst, nil ist ein anderer 'falsey' Wert
|
||||
```
|
||||
!nil #=> true
|
||||
!false #=> true
|
||||
!0 #=> false
|
||||
```
|
||||
### Weitere Vergleiche
|
||||
```
|
||||
1 < 10 #=> true
|
||||
1 > 10 #=> false
|
||||
2 <= 2 #=> true
|
||||
2 >= 2 #=> true
|
||||
```
|
||||
### Logische Operatoren
|
||||
```
|
||||
true && false #=> false
|
||||
true || false #=> true
|
||||
!true #=> false
|
||||
```
|
||||
|
||||
Es gibt alternative Versionen der logischen Operatoren mit niedrigerer
|
||||
Wertigkeit. Diese werden meistens bei Flow-Control eingesetzt, um
|
||||
verschiedenen Ausdrücke zu verketten bis einer true oder false zurück
|
||||
liefert.
|
||||
|
||||
#### and
|
||||
##### `do_something_else` wird nur ausgewertet wenn `do_something` true ist.
|
||||
do_something() and do_something_else()
|
||||
|
||||
#### or
|
||||
#####`log_error` wird nur ausgewertet wenn `do_something` false ist.
|
||||
do_something() or log_error()
|
||||
|
||||
## Strings sind Objekte
|
||||
```
|
||||
'I am a string'.class #=> String
|
||||
"I am a string too".class #=> String
|
||||
|
||||
|
||||
platzhalter = 'Ruby'
|
||||
"Ich kann in #{placeholder} Platzhalter mit doppelten Anführungsstrichen füllen."
|
||||
```
|
||||
Einfache Anführungszeichen sollten bevorzugt werden.
|
||||
Doppelte Anführungszeichen führen interne Berechnungen durch.
|
||||
|
||||
### Strings können verbunden werden, aber nicht mit Zahlen
|
||||
```
|
||||
'hello ' + 'world' #=> "hello world"
|
||||
'hello ' + 3 #=> TypeError: can't convert Fixnum into String
|
||||
```
|
||||
#### Zahl muss in String konvertiert werden
|
||||
```
|
||||
'hello ' + 3.to_s #=> "hello 3"
|
||||
```
|
||||
### Text ausgeben
|
||||
```
|
||||
puts "I'm printing!"
|
||||
```
|
||||
# Variablen
|
||||
## Zuweisungen
|
||||
### Diese Zuweisung gibt den zugeordneten Wert zurück
|
||||
```
|
||||
x = 25 #=> 25
|
||||
x #=> 25
|
||||
```
|
||||
### Damit funktionieren auch mehrfache Zuweisungen
|
||||
```
|
||||
x = y = 10 #=> 10
|
||||
x #=> 10
|
||||
y #=> 10
|
||||
```
|
||||
## Benennung
|
||||
### Konvention ist snake_case
|
||||
```
|
||||
snake_case = true
|
||||
```
|
||||
### Benutze verständliche Variablennamen
|
||||
```
|
||||
path_to_project_root = '/good/name/'
|
||||
path = '/bad/name/'
|
||||
```
|
||||
# Symbols (sind auch Objekte)
|
||||
Symbols sind unveränderliche, wiederverwendbare Konstanten, welche intern
|
||||
als integer repräsentiert werden. Sie werden häufig anstelle von Strings
|
||||
verwendet, um sinnvoll Werte zu übermitteln.
|
||||
Symbols werden mit dem Doppelpunkt gekennzeichnet.
|
||||
|
||||
```
|
||||
:pending.class #=> Symbol
|
||||
status = :pending
|
||||
status == :pending #=> true
|
||||
status == 'pending' #=> false
|
||||
status == :approved #=> false
|
||||
```
|
||||
# Arrays
|
||||
|
||||
## Ein Array anlegen
|
||||
```
|
||||
array = [1, 2, 3, 4, 5] #=> [1, 2, 3, 4, 5]
|
||||
```
|
||||
|
||||
## Array können verschiedene Typen beinhalten
|
||||
```
|
||||
[1, 'hello', false] #=> [1, "hello", false]
|
||||
```
|
||||
|
||||
## Wie bei arithmetischen Ausdrücken auch wird beim Zugriff auf
|
||||
## [0] eigentlich die Methode [] des Array Objekts aufgerufen.
|
||||
```
|
||||
array.[] 0 #=> 1
|
||||
array.[] 12 #=> nil
|
||||
```
|
||||
|
||||
## Arrays können von vorne indiziert werden
|
||||
```
|
||||
array[0] #=> 1
|
||||
array[12] #=> nil
|
||||
```
|
||||
|
||||
## Arrays können von hinten indiziert werden
|
||||
```
|
||||
array[-1] #=> 5
|
||||
```
|
||||
|
||||
## Arrays können mit Stard Index und Länge indiziert werden
|
||||
```
|
||||
array[2, 3] #=> [3, 4, 5]
|
||||
```
|
||||
|
||||
## Arrays können mit einer Range indiziert werden
|
||||
```
|
||||
array[1..3] #=> [2, 3, 4]
|
||||
```
|
||||
|
||||
## Einen Wert hinzufügen
|
||||
```
|
||||
array << 6 #=> [1, 2, 3, 4, 5, 6]
|
||||
array.push(6) #=> [1, 2, 3, 4, 5, 6]
|
||||
```
|
||||
|
||||
## Testen, ob ein Element schon vorhanden ist
|
||||
```
|
||||
array.include?(1) #=> true
|
||||
```
|
||||
|
||||
# Hashes
|
||||
Hashes sind das Hauptfeature um Key/Values zu speichern
|
||||
|
||||
```
|
||||
|
||||
## Ein Hash anlegen
|
||||
```
|
||||
hash = { 'color' => 'green', 'number' => 5 }
|
||||
hash.keys #=> ['color', 'number']
|
||||
```
|
||||
|
||||
## Wert per key herausfinden
|
||||
```
|
||||
hash['color'] #=> 'green'
|
||||
hash['number'] #=> 5
|
||||
hash['nothing here'] #=> nil
|
||||
// Asking a hash for a key that doesn't exist returns nil:
|
||||
```
|
||||
|
||||
## Symbols können auch keys sein
|
||||
```
|
||||
new_hash = { defcon: 3, action: true }
|
||||
new_hash.keys #=> [:defcon, :action]
|
||||
```
|
||||
|
||||
## Testen ob ein Key oder ein Value existiert
|
||||
```
|
||||
new_hash.has_key?(:defcon) #=> true
|
||||
new_hash.has_value?(3) #=> true
|
||||
```
|
||||
|
||||
### Tip: Arrays und Hashes sind Enumerable
|
||||
### Und haben gemeinsame, hilfreiche Methoden wie:
|
||||
### each, map, count, and more
|
||||
|
||||
# Kontrolstrukturen
|
||||
## if
|
||||
```
|
||||
if true
|
||||
'if statement'
|
||||
elsif false
|
||||
'else if, optional'
|
||||
else
|
||||
'else, also optional'
|
||||
end
|
||||
```
|
||||
## for - Allerdings werden for Schleifen nicht oft vewendet.
|
||||
```
|
||||
for counter in 1..5
|
||||
puts "iteration #{counter}"
|
||||
end
|
||||
```
|
||||
## Stattdessen: "each" Methode und einen Bloch übergeben
|
||||
Ein Block ist ein Codeteil, den man einer Methode übergeben kann
|
||||
Ähnelt stark lambdas, anonymen Funktionen oder Closures in anderen
|
||||
Programmiersprachen.
|
||||
|
||||
```
|
||||
(1..5).each do |counter|
|
||||
puts "iteration #{counter}"
|
||||
end
|
||||
```
|
||||
|
||||
Die each Methode einer Range führt den Block für jedes Element der Range aus.
|
||||
|
||||
Dem Block wird ein "counter" parameter übergeben.
|
||||
|
||||
### Den Block kann man auch in geschweiften Klammern schreiben
|
||||
```
|
||||
(1..5).each { |counter| puts "iteration #{counter}" }
|
||||
```
|
||||
|
||||
### Each kann auch über den Inhalt von Datenstrukturen iterieren
|
||||
```
|
||||
array.each do |element|
|
||||
puts "#{element} is part of the array"
|
||||
end
|
||||
hash.each do |key, value|
|
||||
puts "#{key} is #{value}"
|
||||
end
|
||||
|
||||
counter = 1
|
||||
while counter <= 5 do
|
||||
puts "iteration #{counter}"
|
||||
counter += 1
|
||||
end
|
||||
```
|
||||
|
||||
## case
|
||||
```
|
||||
grade = 'B'
|
||||
|
||||
case grade
|
||||
when 'A'
|
||||
puts 'Way to go kiddo'
|
||||
when 'B'
|
||||
puts 'Better luck next time'
|
||||
when 'C'
|
||||
puts 'You can do better'
|
||||
when 'D'
|
||||
puts 'Scraping through'
|
||||
when 'F'
|
||||
puts 'You failed!'
|
||||
else
|
||||
puts 'Alternative grading system, eh?'
|
||||
end
|
||||
=> "Better luck next time"
|
||||
```
|
||||
|
||||
### Case können auch ranges
|
||||
```
|
||||
grade = 82
|
||||
case grade
|
||||
when 90..100
|
||||
puts 'Hooray!'
|
||||
when 80...90
|
||||
puts 'OK job'
|
||||
else
|
||||
puts 'You failed!'
|
||||
end
|
||||
=> "OK job"
|
||||
```
|
||||
|
||||
# exception handling:
|
||||
```
|
||||
begin
|
||||
# code here that might raise an exception
|
||||
raise NoMemoryError, 'You ran out of memory.'
|
||||
rescue NoMemoryError => exception_variable
|
||||
puts 'NoMemoryError was raised', exception_variable
|
||||
rescue RuntimeError => other_exception_variable
|
||||
puts 'RuntimeError was raised now'
|
||||
else
|
||||
puts 'This runs if no exceptions were thrown at all'
|
||||
ensure
|
||||
puts 'This code always runs no matter what'
|
||||
end
|
||||
```
|
||||
# Funktionen
|
||||
```
|
||||
def double(x)
|
||||
x * 2
|
||||
end
|
||||
```
|
||||
## Funktionen (und Blocks)
|
||||
## geben implizit den Wert des letzten Statements zurück
|
||||
```
|
||||
double(2) #=> 4
|
||||
```
|
||||
|
||||
### Klammern sind optional wenn das Ergebnis nicht mehdeutig ist
|
||||
```
|
||||
double 3 #=> 6
|
||||
double double 3 #=> 12
|
||||
def sum(x, y)
|
||||
x + y
|
||||
end
|
||||
```
|
||||
|
||||
### Methoden Parameter werden per Komma getrennt
|
||||
```
|
||||
sum 3, 4 #=> 7
|
||||
sum sum(3, 4), 5 #=> 12
|
||||
```
|
||||
|
||||
## yield
|
||||
### Alle Methoden haben einen impliziten, optionalen block Parameter
|
||||
### Dieser wird mit dem Schlüsselword "yield" aufgerufen
|
||||
```
|
||||
def surround
|
||||
puts '{'
|
||||
yield
|
||||
puts '}'
|
||||
end
|
||||
surround { puts 'hello world' }
|
||||
```
|
||||
|
||||
## Einen Block kann man auch einer Methoden übergeben
|
||||
### "&" kennzeichnet die Referenz zum übergebenen Block
|
||||
```
|
||||
def guests(&block)
|
||||
block.call 'some_argument'
|
||||
end
|
||||
```
|
||||
|
||||
### Eine Liste von Parametern kann man auch übergeben,
|
||||
### Diese wird in ein Array konvertiert
|
||||
### "*" kennzeichnet dies.
|
||||
```
|
||||
def guests(*array)
|
||||
array.each { |guest| puts guest }
|
||||
end
|
||||
```
|
||||
# Klassen
|
||||
## Werden mit dem class Schlüsselwort definiert
|
||||
```
|
||||
class Human
|
||||
```
|
||||
|
||||
### Konstruktor bzw. Initializer
|
||||
```
|
||||
def initialize(name, age = 0)
|
||||
# Assign the argument to the "name" instance variable for the instance
|
||||
@name = name
|
||||
# If no age given, we will fall back to the default in the arguments list.
|
||||
@age = age
|
||||
end
|
||||
```
|
||||
|
||||
### setter Methode
|
||||
```
|
||||
def name=(name)
|
||||
@name = name
|
||||
end
|
||||
```
|
||||
### getter Methode
|
||||
```
|
||||
def name
|
||||
@name
|
||||
end
|
||||
```
|
||||
|
||||
#### getter können mit der attr_accessor Methode vereinfacht definiert werden
|
||||
```
|
||||
attr_accessor :name
|
||||
# Getter/setter methods can also be created individually like this
|
||||
attr_reader :name
|
||||
attr_writer :name
|
||||
# A class method uses self to distinguish from instance methods.
|
||||
# It can only be called on the class, not an instance.
|
||||
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')
|
||||
```
|
||||
|
||||
## Methodenaufrufe
|
||||
```
|
||||
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"
|
||||
```
|
||||
|
||||
## Eine Klassenmethode aufrufen
|
||||
```
|
||||
Human.say('Hi') #=> "Hi"
|
||||
```
|
||||
|
||||
## Variable Gültigkeit
|
||||
### Variablen die mit "$" starten, gelten global
|
||||
```
|
||||
$var = "I'm a global var"
|
||||
defined? $var #=> "global-variable"
|
||||
```
|
||||
|
||||
### Variablen die mit "@" starten, gelten für die Instanz
|
||||
```
|
||||
@var = "I'm an instance var"
|
||||
defined? @var #=> "instance-variable"
|
||||
```
|
||||
|
||||
### Variablen die mit "@@" starten, gelten für die Klasse
|
||||
```
|
||||
@@var = "I'm a class var"
|
||||
defined? @@var #=> "class variable"
|
||||
```
|
||||
|
||||
### Variablen die mit einem Großbuchstaben anfangen, sind Konstanten
|
||||
```
|
||||
Var = "I'm a constant"
|
||||
defined? Var #=> "constant"
|
||||
```
|
||||
|
||||
## Class ist auch ein Objekt
|
||||
### Hat also auch Instanzvariablen
|
||||
### Eine Klassenvariable wird innerhalb der Klasse und Ableitungen geteilt.
|
||||
|
||||
### Basis Klasse
|
||||
```
|
||||
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 # 2
|
||||
```
|
||||
|
||||
### Eine Klasseninstanzvariable wird nicht geteilt
|
||||
```
|
||||
class Human
|
||||
@bar = 0
|
||||
def self.bar
|
||||
@bar
|
||||
end
|
||||
def self.bar=(value)
|
||||
@bar = value
|
||||
end
|
||||
end
|
||||
```
|
||||
```
|
||||
class Doctor < Human
|
||||
end
|
||||
```
|
||||
```
|
||||
Human.bar # 0
|
||||
Doctor.bar # nil
|
||||
```
|
||||
```
|
||||
module ModuleExample
|
||||
def foo
|
||||
'foo'
|
||||
end
|
||||
end
|
||||
```
|
||||
### Module einbinden, heisst ihre Methoden an die Instanzen der Klasse zu binden
|
||||
### Module erweitern, heisst ihre Mothden an die Klasse selbst zu binden
|
||||
```
|
||||
class Person
|
||||
include ModuleExample
|
||||
end
|
||||
```
|
||||
```
|
||||
class Book
|
||||
extend ModuleExample
|
||||
end
|
||||
```
|
||||
```
|
||||
Person.foo # => NoMethodError: undefined method `foo' for Person:Class
|
||||
Person.new.foo # => 'foo'
|
||||
Book.foo # => 'foo'
|
||||
Book.new.foo # => NoMethodError: undefined method `foo'
|
||||
```
|
||||
### Callbacks werden ausgeführt, wenn ein Modul eingebunden oder erweitert wird
|
||||
```
|
||||
module ConcernExample
|
||||
def self.included(base)
|
||||
base.extend(ClassMethods)
|
||||
base.send(:include, InstanceMethods)
|
||||
end
|
||||
module ClassMethods
|
||||
def bar
|
||||
'bar'
|
||||
end
|
||||
end
|
||||
module InstanceMethods
|
||||
def qux
|
||||
'qux'
|
||||
end
|
||||
end
|
||||
end
|
||||
class Something
|
||||
include ConcernExample
|
||||
end
|
||||
```
|
||||
```
|
||||
Something.bar # => 'bar'
|
||||
Something.qux # => NoMethodError: undefined method `qux'
|
||||
Something.new.bar # => NoMethodError: undefined method `bar'
|
||||
Something.new.qux # => 'qux'
|
||||
```
|
||||
|
||||
## Weiterführende Hinweise
|
||||
|
||||
//EN
|
||||
|
||||
- [Learn Ruby by Example with Challenges](http://www.learneroo.com/modules/61/nodes/338) - A variant of this reference with in-browser challenges.
|
||||
- [Official Documentation](http://www.ruby-doc.org/core-2.1.1/)
|
||||
- [Ruby from other languages](https://www.ruby-lang.org/en/documentation/ruby-from-other-languages/)
|
||||
- [Programming Ruby](http://www.amazon.com/Programming-Ruby-1-9-2-0-Programmers/dp/1937785491/) - An older [free edition](http://ruby-doc.com/docs/ProgrammingRuby/) is available online.
|
||||
- [Ruby Style Guide](https://github.com/bbatsov/ruby-style-guide) - A community-driven Ruby coding style guide.
|
149
de-de/ruby-ecosystem-de.html.markdown
Normal file
149
de-de/ruby-ecosystem-de.html.markdown
Normal file
@ -0,0 +1,149 @@
|
||||
---
|
||||
category: tool
|
||||
tool: ruby ecosystem
|
||||
contributors:
|
||||
- ["Jon Smock", "http://github.com/jonsmock"]
|
||||
- ["Rafal Chmiel", "http://github.com/rafalchmiel"]
|
||||
translators:
|
||||
- ["Christian Albrecht", "https://github.com/coastalchief"]
|
||||
filename: ruby-ecosystem-de.html.markdown
|
||||
lang: de-de
|
||||
---
|
||||
|
||||
Hier gibt es einen Überblick über die gängigsten Tools zur Verwaltung
|
||||
von verschiedenen Ruby Versionen, Gems und Dependencies.
|
||||
|
||||
## Ruby Managers
|
||||
|
||||
Einige Betriebssysteme haben bereits eine Ruby Version vorinstalliert
|
||||
oder bieten sie als Package zum Download an. Die meisten Rubyisten
|
||||
benutzen diese aber eher nicht und wenn, dann um damit einen Ruby
|
||||
Manager zu installieren. Damit kann man komfortabel zwischen den
|
||||
verschiedenen Versionen hin und herspringen.
|
||||
|
||||
Dies sind die beliebtesten:
|
||||
|
||||
* [RVM](https://rvm.io/) - Installiert und wechselt zwischen rubies
|
||||
RVM kennt verschiedene Ruby Versionen und hat das Konzept der gemsets,
|
||||
um gem Abhängigkeiten pro Projekt zu managen.
|
||||
* [ruby-build](https://github.com/sstephenson/ruby-build)
|
||||
Installiert nur rubies, kann diese aber sehr gut verwalten
|
||||
* [rbenv](https://github.com/sstephenson/rbenv) - Wechselt Ruby Versionen.
|
||||
Wird zusammen mit ruby-build benutzt. Hiermit kann man kontrollieren,
|
||||
wie rubies laden.
|
||||
* [chruby](https://github.com/postmodern/chruby) - Wechselt Ruby Versionen.
|
||||
Ähnlich rbenv.
|
||||
|
||||
## Ruby Versionen
|
||||
|
||||
Ruby wurde von Yukihiro "Matz" Matsumoto vor gut 20 Jahren veröffentlicht.
|
||||
Matz ist nach wie vor in die Entwicklung involviert. Daher kommt auch der
|
||||
Name der Referenzimplementierung: MRI (Matz' Reference Implementation).
|
||||
|
||||
Die aktuellste Version ist **2.2.3** und wurde im August 2015 veröffentlicht!
|
||||
|
||||
Hier eine kurze Versionshistorie:
|
||||
|
||||
* 2.0.0 - Release im Februar 2013 -- Release zum 20. Geburtstag der Sprache
|
||||
[Rubies are forever](http://www.heise.de/developer/artikel/Ruby-2-0-als-Geschenk-zum-20-Geburtstag-1808109.html)
|
||||
* 1.9.3 - Release im Oktober 2011
|
||||
[End of Life](https://www.ruby-lang.org/en/news/2015/02/23/support-for-ruby-1-9-3-has-ended/)
|
||||
* 1.8.7 - Release im Juni 2006
|
||||
[End of Life](http://www.ruby-lang.org/en/news/2013/06/30/we-retire-1-8-7/).
|
||||
|
||||
Die Veränderung zwischen 1.8.7 und 1.9.x war sehr groß und eine Migration
|
||||
nicht so einfach möglich. Der Versionssprung auf 2.0.0 war verglichen dazu
|
||||
weit weniger dramatisch.
|
||||
Beispielsweise hat 1.9. Encodings und eine Bytecode VM eingeführt.
|
||||
Es gibt immer noch Projekte die auf der stabilen Version 1.8.7 laufen,
|
||||
aber diese sind mittlerweile in der Minderheit. Die meisten Projekte
|
||||
laufen auf 1.9.x oder auf 2.x.
|
||||
|
||||
## Ruby Implementierungen
|
||||
|
||||
Das Ruby Ecosystem beinhaltet viele verschiedene Implementierungen von Ruby,
|
||||
jedes mit seinen eigenen Vorteilen und verschiedenen Graden von
|
||||
Kompatibilität. Auch wenn alle diese Implementierungen in verschiedenen
|
||||
Sprachen geschrieben sind, sind sie doch **alle Ruby**.
|
||||
Jede Implementierung bietet neben ihren speziellen Features immer auch
|
||||
die Möglichkeit normale ruby Dateien auszuführen.
|
||||
|
||||
Am ausgereiftesten und stabilsten:
|
||||
|
||||
* [MRI](https://github.com/ruby/ruby) - Geschrieben in C, das ist die Referenz Implementierung.
|
||||
Sie ist 100% kompatibel (mit sich selbst ;-). Alle anderen rubies
|
||||
bleiben kompatibel mit MRI (siehe [RubySpec](#rubyspec) weiter unten).
|
||||
* [JRuby](http://jruby.org/) - Geschrieben in Java and Ruby, Robust und ziemlich schnell.
|
||||
Der größte Vorteil von JRuby ist die Interoperabilität mit JVM/Java und damit die
|
||||
Benutzung von Ruby im Java Ecosystem.
|
||||
* [Rubinius](http://rubini.us/) - Geschrieben in Ruby mit C++ bytecode VM.
|
||||
Auch sehr ausgereift und schnell.
|
||||
|
||||
Mittel ausgereift / kompatibel:
|
||||
|
||||
* [Maglev](http://maglev.github.io/) - Baut auf Gemstone, ein Smalltalk VM.
|
||||
Dieses Projekt versucht das großartige Smalltalk Tooling in die Ruby Welt
|
||||
zu bringen.
|
||||
* [RubyMotion](http://www.rubymotion.com/) - Ruby in der iOS Entwicklung.
|
||||
|
||||
Weniger ausgereift/kompatibel:
|
||||
|
||||
* [Topaz](http://topazruby.com/) - Geschrieben in RPython (via PyPy)
|
||||
Topaz ist noch ziemlich jung und versucht die schnellste Implementierung
|
||||
zu werden.
|
||||
* [IronRuby](http://ironruby.net/) - Geschrieben in C# für die .NET Plaftform
|
||||
Das letzte Release von IronRuby ist mittlerweile 5 Jahre her.
|
||||
|
||||
Die Ruby Implementierungen haben ihre eigenen Versionsnummern, sind aber
|
||||
trotzdem immer zu einer MRI Version kompatibel.
|
||||
Viele können sogar zwischen verschiedenen Modi wechseln (1.8 mode -> 1.9 mode)
|
||||
|
||||
## RubySpec
|
||||
|
||||
Die meisten Ruby Implementierungen vertrauen der [RubySpec](http://rubyspec.org/).
|
||||
sehr stark. Da Ruby keine offizielle Spezifikation hat, hat die
|
||||
Community ausführbare Specs (in Ruby) geschrieben, um so die Kompatibilität
|
||||
zur MRI testen zu können.
|
||||
|
||||
## RubyGems
|
||||
|
||||
[RubyGems](http://rubygems.org/) ist der Community Paket Manager von Ruby.
|
||||
RubyGems kommt mit Ruby zusammen, so dass kein extra Tool nötig ist.
|
||||
|
||||
Ruby Pakete werden "gems" genannt und könnten auf RubyGems.org
|
||||
veröffentlicht werden. Jedes Gem enthält den Source Code und Meta Daten,
|
||||
wie die Versionsnummer, weitere Abhängigkeiten, Autoren und Lizenzen.
|
||||
|
||||
## Bundler
|
||||
|
||||
[Bundler](http://bundler.io/) ist ein Tool um Abhängigkeiten zwischen
|
||||
Gems aufzulösen und zu managen. Dazu werden diese in einem gemfile
|
||||
zusammengefasst und Bundler kümmert sich darum die Abhängigkeiten
|
||||
untereinander rekursiv aufzulösen. Entweder es klappt und alle gems
|
||||
konnten runtergeladen werden, oder es wird abgebrochen und
|
||||
der Konflikt gemeldet.
|
||||
Zum Beispiel:
|
||||
Wenn Gem A die Version 3 oder höher von Gem Z braucht, aber Gem B
|
||||
von Gem Z die Version 2, dann ist das ein Konflikt.
|
||||
|
||||
# Testing
|
||||
|
||||
Test-Driven Development ist ein essentieller Teil der Ruby Kultur.
|
||||
Ruby bringt sein eigenes Unit-Test framework mit, minitest. Darüberhinaus
|
||||
gibt es noch viele weitere Testframeworks mit unterschiedlichsten Zielen:
|
||||
|
||||
* [TestUnit](http://ruby-doc.org/stdlib-1.8.7/libdoc/test/unit/rdoc/Test/Unit.html) - Eingebaut in Ruby 1.8
|
||||
"Unit-style" Testframework
|
||||
* [minitest](http://ruby-doc.org/stdlib-2.0.0/libdoc/minitest/rdoc/MiniTest.html) - Eingebaut in Ruby 1.9/2.0
|
||||
"Unit-style" Testframework
|
||||
* [RSpec](http://rspec.info/) - Ein Testframework welches auf verständliche Testdefinition setzt
|
||||
* [Cucumber](http://cukes.info/) - Ein BDD Testframework welches Gherkin tests parsen kann
|
||||
|
||||
## Be Nice
|
||||
Die Ruby Community ist stolz darauf eine offene, vielfältige und einladende
|
||||
Community zu sein. Es gibt viele aktive Ruby User Gruppen und diverse
|
||||
Ruby Konferenzen. Matz selbst ist so oft es geht dabei.
|
||||
|
||||
* [Euruko](http://www.euruko2015.org)
|
||||
* [User Groups](https://www.ruby-lang.org/de/community/user-groups/)
|
||||
|
816
de-de/scala-de.html.markdown
Normal file
816
de-de/scala-de.html.markdown
Normal file
@ -0,0 +1,816 @@
|
||||
---
|
||||
language: Scala
|
||||
contributors:
|
||||
- ["George Petrov", "http://github.com/petrovg"]
|
||||
- ["Dominic Bou-Samra", "http://dbousamra.github.com"]
|
||||
- ["Geoff Liu", "http://geoffliu.me"]
|
||||
- ["Ha-Duong Nguyen", "http://reference-error.org"]
|
||||
translators:
|
||||
- ["Christian Albrecht", "https://github.com/coastalchief"]
|
||||
filename: scala-de.html.markdown
|
||||
lang: de-de
|
||||
---
|
||||
|
||||
Scala ist eine funktionale und objektorientierte Programmiersprache
|
||||
für die Java Virtual Machine (JVM), um allgemeine Programmieraufgaben
|
||||
zu erledigen. Scala hat einen akademischen Hintergrund und wurde an
|
||||
der EPFL (Lausanne / Schweiz) unter der Leitung von Martin Odersky entwickelt.
|
||||
|
||||
|
||||
# 0. Umgebung einrichten
|
||||
Scala Umgebung einrichten:
|
||||
|
||||
1. Scala binaries herunterladen- http://www.scala-lang.org/downloads
|
||||
2. Unzip/untar in ein Verzeichnis
|
||||
3. das bin Unterverzeichnis der `PATH` Umgebungsvariable hinzufügen
|
||||
4. Mit dem Kommando `scala` wird die REPL gestartet und zeigt als Prompt:
|
||||
```
|
||||
scala>
|
||||
```
|
||||
|
||||
Die REPL (Read-Eval-Print Loop) ist der interaktive Scala Interpreter.
|
||||
Hier kann man jeden Scala Ausdruck verwenden und das Ergebnis wird direkt
|
||||
ausgegeben.
|
||||
Als nächstes beschäftigen wir uns mit ein paar Scala Basics.
|
||||
|
||||
# 1. Basics
|
||||
|
||||
Einzeilige Kommentare beginnen mit zwei vorwärts Slash
|
||||
|
||||
/*
|
||||
Mehrzeilige Kommentare, werden starten
|
||||
mit Slash-Stern und enden mit Stern-Slash
|
||||
*/
|
||||
|
||||
// Einen Wert, und eine zusätzliche neue Zeile ausgeben
|
||||
```
|
||||
println("Hello world!")
|
||||
println(10)
|
||||
```
|
||||
|
||||
// Einen Wert, ohne eine zusätzliche neue Zeile ausgeben
|
||||
```
|
||||
print("Hello world")
|
||||
```
|
||||
|
||||
// Variablen werden entweder mit var oder val deklariert.
|
||||
// Deklarationen mit val sind immutable, also unveränderlich
|
||||
// Deklarationen mit var sind mutable, also veränderlich
|
||||
// Immutability ist gut.
|
||||
```
|
||||
val x = 10 // x ist 10
|
||||
x = 20 // error: reassignment to val
|
||||
var y = 10
|
||||
y = 20 // y ist jetzt 20
|
||||
```
|
||||
|
||||
Scala ist eine statisch getypte Sprache, auch wenn in dem o.g. Beispiel
|
||||
keine Typen an x und y geschrieben haben.
|
||||
In Scala ist etwas eingebaut, was sich Type Inference nennt. D.h. das der
|
||||
Scala Compiler in den meisten Fällen erraten kann, von welchen Typ eine ist,
|
||||
so dass der Typ nicht jedes mal angegeben werden soll.
|
||||
Einen Typ gibt man bei einer Variablendeklaration wie folgt an:
|
||||
```
|
||||
val z: Int = 10
|
||||
val a: Double = 1.0
|
||||
```
|
||||
|
||||
// Bei automatischer Umwandlung von Int auf Double wird aus 10 eine 10.0
|
||||
```
|
||||
val b: Double = 10
|
||||
```
|
||||
|
||||
// Boolean Werte
|
||||
```
|
||||
true
|
||||
false
|
||||
```
|
||||
|
||||
// Boolean Operationen
|
||||
```
|
||||
!true // false
|
||||
!false // true
|
||||
true == false // false
|
||||
10 > 5 // true
|
||||
```
|
||||
|
||||
// Mathematische Operationen sind wie gewohnt
|
||||
```
|
||||
1 + 1 // 2
|
||||
2 - 1 // 1
|
||||
5 * 3 // 15
|
||||
6 / 2 // 3
|
||||
6 / 4 // 1
|
||||
6.0 / 4 // 1.5
|
||||
```
|
||||
|
||||
// Die Auswertung eines Ausdrucks in der REPL gibt den Typ
|
||||
// und das Ergebnis zurück.
|
||||
```
|
||||
scala> 1 + 7
|
||||
res29: Int = 8
|
||||
```
|
||||
|
||||
Das bedeutet, dass das Resultat der Auswertung von 1 + 7 ein Objekt
|
||||
von Typ Int ist und einen Wert 0 hat.
|
||||
"res29" ist ein sequentiell generierter name, um das Ergebnis des
|
||||
Ausdrucks zu speichern. Dieser Wert kann bei Dir anders sein...
|
||||
|
||||
|
||||
"Scala strings werden in doppelten Anführungszeichen eingeschlossen"
|
||||
'a' // A Scala Char
|
||||
// 'Einzeln ge-quotete strings gibt es nicht!' <= This causes an error
|
||||
|
||||
// Für Strings gibt es die üblichen Java Methoden
|
||||
```
|
||||
"hello world".length
|
||||
"hello world".substring(2, 6)
|
||||
"hello world".replace("C", "3")
|
||||
```
|
||||
|
||||
// Zusätzlich gibt es noch extra Scala Methoden
|
||||
// siehe: scala.collection.immutable.StringOps
|
||||
```
|
||||
"hello world".take(5)
|
||||
"hello world".drop(5)
|
||||
```
|
||||
|
||||
// String interpolation: prefix "s"
|
||||
```
|
||||
val n = 45
|
||||
s"We have $n apples" // => "We have 45 apples"
|
||||
```
|
||||
|
||||
// Ausdrücke im innern von interpolierten Strings gibt es auch
|
||||
```
|
||||
val a = Array(11, 9, 6)
|
||||
val n = 100
|
||||
s"My second daughter is ${a(0) - a(2)} years old." // => "My second daughter is 5 years old."
|
||||
s"We have double the amount of ${n / 2.0} in apples." // => "We have double the amount of 22.5 in apples."
|
||||
s"Power of 2: ${math.pow(2, 2)}" // => "Power of 2: 4"
|
||||
```
|
||||
|
||||
// Formatierung der interpolierten Strings mit dem prefix "f"
|
||||
```
|
||||
f"Power of 5: ${math.pow(5, 2)}%1.0f" // "Power of 5: 25"
|
||||
f"Square root of 122: ${math.sqrt(122)}%1.4f" // "Square root of 122: 11.0454"
|
||||
```
|
||||
|
||||
// Raw Strings, ignorieren Sonderzeichen.
|
||||
```
|
||||
raw"New line feed: \n. Carriage return: \r." // => "New line feed: \n. Carriage return: \r."
|
||||
```
|
||||
|
||||
// Manche Zeichen müssen "escaped" werden, z.B.
|
||||
// ein doppeltes Anführungszeichen in innern eines Strings.
|
||||
```
|
||||
"They stood outside the \"Rose and Crown\"" // => "They stood outside the "Rose and Crown""
|
||||
```
|
||||
|
||||
// Dreifache Anführungszeichen erlauben es, dass ein String über mehrere Zeilen geht
|
||||
// und Anführungszeichen enthalten kann.
|
||||
```
|
||||
val html = """<form id="daform">
|
||||
<p>Press belo', Joe</p>
|
||||
<input type="submit">
|
||||
</form>"""
|
||||
```
|
||||
|
||||
# 2. Funktionen
|
||||
|
||||
// Funktionen werden so definiert
|
||||
//
|
||||
// def functionName(args...): ReturnType = { body... }
|
||||
//
|
||||
// Beachte: Es gibt kein return Schlüsselwort. In Scala ist der letzte Ausdruck
|
||||
// in einer Funktion der Rückgabewert.
|
||||
```
|
||||
def sumOfSquares(x: Int, y: Int): Int = {
|
||||
val x2 = x * x
|
||||
val y2 = y * y
|
||||
x2 + y2
|
||||
}
|
||||
```
|
||||
|
||||
// Die geschweiften Klammern können weggelassen werden, wenn
|
||||
// die Funktion nur aus einem einzigen Ausdruck besteht:
|
||||
```
|
||||
def sumOfSquaresShort(x: Int, y: Int): Int = x * x + y * y
|
||||
```
|
||||
|
||||
// Syntax für Funktionsaufrufe:
|
||||
```
|
||||
sumOfSquares(3, 4) // => 25
|
||||
```
|
||||
|
||||
// In den meisten Fällen (mit Ausnahme von rekursiven Funktionen), können
|
||||
// Rückgabetypen auch weggelassen werden, da dieselbe Typ Inference, wie bei
|
||||
// Variablen, auch bei Funktionen greift:
|
||||
```
|
||||
def sq(x: Int) = x * x // Compiler errät, dass der return type Int ist
|
||||
```
|
||||
|
||||
// Funktionen können default parameter haben:
|
||||
```
|
||||
def addWithDefault(x: Int, y: Int = 5) = x + y
|
||||
addWithDefault(1, 2) // => 3
|
||||
addWithDefault(1) // => 6
|
||||
```
|
||||
|
||||
// Anonyme Funktionen sehen so aus:
|
||||
```
|
||||
(x: Int) => x * x
|
||||
```
|
||||
|
||||
// Im Gegensatz zu def bei normalen Funktionen, kann bei anonymen Funktionen
|
||||
// sogar der Eingabetyp weggelassen werden, wenn der Kontext klar ist.
|
||||
// Beachte den Typ "Int => Int", dies beschreibt eine Funktion,
|
||||
// welche Int als Parameter erwartet und Int zurückgibt.
|
||||
```
|
||||
val sq: Int => Int = x => x * x
|
||||
```
|
||||
|
||||
// Anonyme Funktionen benutzt man ganz normal:
|
||||
```
|
||||
sq(10) // => 100
|
||||
```
|
||||
|
||||
// Wenn ein Parameter einer anonymen Funktion nur einmal verwendet wird,
|
||||
// bietet Scala einen sehr kurzen Weg diesen Parameter zu benutzen,
|
||||
// indem die Parameter als Unterstrich "_" in der Parameterreihenfolge
|
||||
// verwendet werden. Diese anonymen Funktionen werden sehr häufig
|
||||
// verwendet.
|
||||
```
|
||||
val addOne: Int => Int = _ + 1
|
||||
val weirdSum: (Int, Int) => Int = (_ * 2 + _ * 3)
|
||||
addOne(5) // => 6
|
||||
weirdSum(2, 4) // => 16
|
||||
```
|
||||
|
||||
// Es gibt einen keyword return in Scala. Allerdings ist seine Verwendung
|
||||
// nicht immer ratsam und kann fehlerbehaftet sein. "return" gibt nur aus
|
||||
// dem innersten def, welches den return Ausdruck umgibt, zurück.
|
||||
// "return" hat keinen Effekt in anonymen Funktionen:
|
||||
```
|
||||
def foo(x: Int): Int = {
|
||||
val anonFunc: Int => Int = { z =>
|
||||
if (z > 5)
|
||||
return z // Zeile macht z zum return Wert von foo
|
||||
else
|
||||
z + 2 // Zeile ist der return Wert von anonFunc
|
||||
}
|
||||
anonFunc(x) // Zeile ist der return Wert von foo
|
||||
}
|
||||
```
|
||||
|
||||
# 3. Flow Control
|
||||
|
||||
## Wertebereiche und Schleifen
|
||||
```
|
||||
1 to 5
|
||||
val r = 1 to 5
|
||||
r.foreach(println)
|
||||
r foreach println
|
||||
(5 to 1 by -1) foreach (println)
|
||||
```
|
||||
// Scala ist syntaktisch sehr grosszügig, Semikolons am Zeilenende
|
||||
// sind optional, beim Aufruf von Methoden können die Punkte
|
||||
// und Klammern entfallen und Operatoren sind im Grunde austauschbare Methoden
|
||||
|
||||
// while Schleife
|
||||
```
|
||||
var i = 0
|
||||
while (i < 10) { println("i " + i); i += 1 }
|
||||
i // i ausgeben, res3: Int = 10
|
||||
```
|
||||
|
||||
// Beachte: while ist eine Schleife im klassischen Sinne -
|
||||
// Sie läuft sequentiell ab und verändert die loop-Variable.
|
||||
// While in Scala läuft schneller ab als in Java und die o.g.
|
||||
// Kombinatoren und Zusammenlegungen sind einfacher zu verstehen
|
||||
// und zu parellelisieren.
|
||||
|
||||
// Ein do while Schleife
|
||||
```
|
||||
do {
|
||||
println("x ist immer noch weniger wie 10")
|
||||
x += 1
|
||||
} while (x < 10)
|
||||
```
|
||||
|
||||
// Endrekursionen sind ideomatisch um sich wiederholende
|
||||
// Dinge in Scala zu lösen. Rekursive Funtionen benötigen explizit einen
|
||||
// return Typ, der Compiler kann ihn nicht erraten.
|
||||
// Unit, in diesem Beispiel.
|
||||
```
|
||||
def showNumbersInRange(a: Int, b: Int): Unit = {
|
||||
print(a)
|
||||
if (a < b)
|
||||
showNumbersInRange(a + 1, b)
|
||||
}
|
||||
showNumbersInRange(1, 14)
|
||||
```
|
||||
|
||||
## Conditionals
|
||||
```
|
||||
val x = 10
|
||||
if (x == 1) println("yeah")
|
||||
if (x == 10) println("yeah")
|
||||
if (x == 11) println("yeah")
|
||||
if (x == 11) println ("yeah") else println("nay")
|
||||
println(if (x == 10) "yeah" else "nope")
|
||||
val text = if (x == 10) "yeah" else "nope"
|
||||
```
|
||||
|
||||
# 4. Daten Strukturen (Array, Map, Set, Tuples)
|
||||
|
||||
## Array
|
||||
```
|
||||
val a = Array(1, 2, 3, 5, 8, 13)
|
||||
a(0)
|
||||
a(3)
|
||||
a(21) // Exception
|
||||
```
|
||||
|
||||
## Map - Speichert Key-Value-Paare
|
||||
```
|
||||
val m = Map("fork" -> "tenedor", "spoon" -> "cuchara", "knife" -> "cuchillo")
|
||||
m("fork")
|
||||
m("spoon")
|
||||
m("bottle") // Exception
|
||||
val safeM = m.withDefaultValue("no lo se")
|
||||
safeM("bottle")
|
||||
```
|
||||
## Set - Speichert Unikate, unsortiert (sortiert -> SortedSet)
|
||||
```
|
||||
val s = Set(1, 3, 7)
|
||||
s(0) //false
|
||||
s(1) //true
|
||||
val s = Set(1,1,3,3,7)
|
||||
s: scala.collection.immutable.Set[Int] = Set(1, 3, 7)
|
||||
```
|
||||
## Tuple - Speichert beliebige Daten und "verbindet" sie miteinander
|
||||
// Ein Tuple ist keine Collection.
|
||||
```
|
||||
(1, 2)
|
||||
(4, 3, 2)
|
||||
(1, 2, "three")
|
||||
(a, 2, "three")
|
||||
```
|
||||
|
||||
// Hier ist der Rückgabewert der Funktion ein Tuple
|
||||
// Die Funktion gibt das Ergebnis, so wie den Rest zurück.
|
||||
```
|
||||
val divideInts = (x: Int, y: Int) => (x / y, x % y)
|
||||
divideInts(10, 3)
|
||||
```
|
||||
|
||||
// Um die Elemente eines Tuples anzusprechen, benutzt man diese
|
||||
// Notation: _._n wobei n der index des Elements ist (Index startet bei 1)
|
||||
```
|
||||
val d = divideInts(10, 3)
|
||||
d._1
|
||||
d._2
|
||||
```
|
||||
# 5. Objekt Orientierte Programmierung
|
||||
|
||||
Bislang waren alle gezeigten Sprachelemente einfache Ausdrücke, welche zwar
|
||||
zum Ausprobieren und Lernen in der REPL gut geeignet sind, jedoch in
|
||||
einem Scala file selten alleine zu finden sind.
|
||||
Die einzigen Top-Level Konstrukte in Scala sind nämlich:
|
||||
|
||||
- Klassen (classes)
|
||||
- Objekte (objects)
|
||||
- case classes
|
||||
- traits
|
||||
|
||||
Diesen Sprachelemente wenden wir uns jetzt zu.
|
||||
|
||||
## Klassen
|
||||
|
||||
// Zum Erstellen von Objekten benötigt man eine Klasse, wie in vielen
|
||||
// anderen Sprachen auch.
|
||||
|
||||
// erzeugt Klasse mit default Konstruktor
|
||||
```
|
||||
class Hund
|
||||
scala> val t = new Hund
|
||||
t: Hund = Hund@7103745
|
||||
```
|
||||
|
||||
// Der Konstruktor wird direkt hinter dem Klassennamen deklariert.
|
||||
```
|
||||
class Hund(sorte: String)
|
||||
scala> val t = new Hund("Dackel")
|
||||
t: Hund = Hund@14be750c
|
||||
scala> t.sorte //error: value sorte is not a member of Hund
|
||||
```
|
||||
|
||||
// Per val wird aus dem Attribut ein unveränderliches Feld der Klasse
|
||||
// Per var wird aus dem Attribut ein veränderliches Feld der Klasse
|
||||
```
|
||||
class Hund(val sorte: String)
|
||||
scala> val t = new Hund("Dackel")
|
||||
t: Hund = Hund@74a85515
|
||||
scala> t.sorte
|
||||
res18: String = Dackel
|
||||
```
|
||||
|
||||
// Methoden werden mit def geschrieben
|
||||
```
|
||||
def bark = "Woof, woof!"
|
||||
```
|
||||
|
||||
// Felder und Methoden können public, protected und private sein
|
||||
// default ist public
|
||||
// private ist nur innerhalb des deklarierten Bereichs sichtbar
|
||||
```
|
||||
class Hund {
|
||||
private def x = ...
|
||||
def y = ...
|
||||
}
|
||||
```
|
||||
|
||||
// protected ist nur innerhalb des deklarierten und aller
|
||||
// erbenden Bereiche sichtbar
|
||||
```
|
||||
class Hund {
|
||||
protected def x = ...
|
||||
}
|
||||
class Dackel extends Hund {
|
||||
// x ist sichtbar
|
||||
}
|
||||
```
|
||||
## Object
|
||||
Wird ein Objekt ohne das Schlüsselwort "new" instanziert, wird das sog.
|
||||
"companion object" aufgerufen. Mit dem "object" Schlüsselwort wird so
|
||||
ein Objekt (Typ UND Singleton) erstellt. Damit kann man dann eine Klasse
|
||||
benutzen ohne ein Objekt instanziieren zu müssen.
|
||||
Ein gültiges companion Objekt einer Klasse ist es aber erst dann, wenn
|
||||
es genauso heisst und in derselben Datei wie die Klasse definiert wurde.
|
||||
```
|
||||
object Hund {
|
||||
def alleSorten = List("Pitbull", "Dackel", "Retriever")
|
||||
def createHund(sorte: String) = new Hund(sorte)
|
||||
}
|
||||
```
|
||||
## Case classes
|
||||
Fallklassen bzw. Case classes sind Klassen die normale Klassen um extra
|
||||
Funktionalität erweitern. Mit Case Klassen bekommt man ein paar
|
||||
Dinge einfach dazu, ohne sich darum kümmern zu müssen. Z.B.
|
||||
ein companion object mit den entsprechenden Methoden,
|
||||
Hilfsmethoden wie toString(), equals() und hashCode() und auch noch
|
||||
Getter für unsere Attribute (das Angeben von val entfällt dadurch)
|
||||
```
|
||||
class Person(val name: String)
|
||||
class Hund(val sorte: String, val farbe: String, val halter: Person)
|
||||
```
|
||||
|
||||
// Es genügt das Schlüsselwort case vor die Klasse zu schreiben.
|
||||
```
|
||||
case class Person(name: String)
|
||||
case class Hund(sorte: String, farbe: String, halter: Person)
|
||||
```
|
||||
|
||||
// Für neue Instanzen brauch man kein "new"
|
||||
```
|
||||
val dackel = Hund("dackel", "grau", Person("peter"))
|
||||
val dogge = Hund("dogge", "grau", Person("peter"))
|
||||
|
||||
```
|
||||
// getter
|
||||
```
|
||||
dackel.halter // => Person = Person(peter)
|
||||
```
|
||||
|
||||
// equals
|
||||
```
|
||||
dogge == dackel // => false
|
||||
```
|
||||
|
||||
// copy
|
||||
// otherGeorge == Person("george", "9876")
|
||||
```
|
||||
val otherGeorge = george.copy(phoneNumber = "9876")
|
||||
```
|
||||
## Traits
|
||||
Ähnlich wie Java interfaces, definiert man mit traits einen Objekttyp
|
||||
und Methodensignaturen. Scala erlaubt allerdings das teilweise
|
||||
implementieren dieser Methoden. Konstruktorparameter sind nicht erlaubt.
|
||||
Traits können von anderen Traits oder Klassen erben, aber nur von
|
||||
parameterlosen.
|
||||
```
|
||||
trait Hund {
|
||||
def sorte: String
|
||||
def farbe: String
|
||||
def bellen: Boolean = true
|
||||
def beissen: Boolean
|
||||
}
|
||||
class Bernhardiner extends Hund{
|
||||
val sorte = "Bernhardiner"
|
||||
val farbe = "braun"
|
||||
def beissen = false
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
scala> b
|
||||
res0: Bernhardiner = Bernhardiner@3e57cd70
|
||||
scala> b.sorte
|
||||
res1: String = Bernhardiner
|
||||
scala> b.bellen
|
||||
res2: Boolean = true
|
||||
scala> b.beissen
|
||||
res3: Boolean = false
|
||||
```
|
||||
|
||||
// Traits können auch via Mixins (Schlüsselwort "with") eingebunden werden
|
||||
```
|
||||
trait Bellen {
|
||||
def bellen: String = "Woof"
|
||||
}
|
||||
trait Hund {
|
||||
def sorte: String
|
||||
def farbe: String
|
||||
}
|
||||
class Bernhardiner extends Hund with Bellen{
|
||||
val sorte = "Bernhardiner"
|
||||
val farbe = "braun"
|
||||
}
|
||||
scala> val b = new Bernhardiner
|
||||
b: Bernhardiner = Bernhardiner@7b69c6ba
|
||||
scala> b.bellen
|
||||
res0: String = Woof
|
||||
```
|
||||
|
||||
# 6. Pattern Matching
|
||||
Pattern matching in Scala ist ein sehr nützliches und wesentlich
|
||||
mächtigeres Feature als Vergleichsfunktionen in Java. In Scala
|
||||
benötigt ein case Statement kein "break", ein fall-through gibt es nicht.
|
||||
Mehrere Überprüfungen können mit einem Statement gemacht werden.
|
||||
Pattern matching wird mit dem Schlüsselwort "match" gemacht.
|
||||
```
|
||||
val x = ...
|
||||
x match {
|
||||
case 2 =>
|
||||
case 3 =>
|
||||
case _ =>
|
||||
}
|
||||
```
|
||||
|
||||
// Pattern Matching kann auf beliebige Typen prüfen
|
||||
```
|
||||
val any: Any = ...
|
||||
val gleicht = any match {
|
||||
case 2 | 3 | 5 => "Zahl"
|
||||
case "woof" => "String"
|
||||
case true | false => "Boolean"
|
||||
case 45.35 => "Double"
|
||||
case _ => "Unbekannt"
|
||||
}
|
||||
```
|
||||
|
||||
// und auf Objektgleichheit
|
||||
```
|
||||
def matchPerson(person: Person): String = person match {
|
||||
case Person("George", nummer) => "George! Die Nummer ist " + number
|
||||
case Person("Kate", nummer) => "Kate! Die Nummer ist " + nummer
|
||||
case Person(name, nummer) => "Irgendjemand: " + name + ", Telefon: " + nummer
|
||||
}
|
||||
```
|
||||
|
||||
// Und viele mehr...
|
||||
```
|
||||
val email = "(.*)@(.*)".r // regex
|
||||
def matchEverything(obj: Any): String = obj match {
|
||||
// Werte:
|
||||
case "Hello world" => "Got the string Hello world"
|
||||
// Typen:
|
||||
case x: Double => "Got a Double: " + x
|
||||
// Conditions:
|
||||
case x: Int if x > 10000 => "Got a pretty big number!"
|
||||
// Case Classes:
|
||||
case Person(name, number) => s"Got contact info for $name!"
|
||||
// RegEx:
|
||||
case email(name, domain) => s"Got email address $name@$domain"
|
||||
// Tuples:
|
||||
case (a: Int, b: Double, c: String) => s"Got a tuple: $a, $b, $c"
|
||||
// Strukturen:
|
||||
case List(1, b, c) => s"Got a list with three elements and starts with 1: 1, $b, $c"
|
||||
// Patterns kann man ineinander schachteln:
|
||||
case List(List((1, 2, "YAY"))) => "Got a list of list of tuple"
|
||||
}
|
||||
```
|
||||
|
||||
// Jedes Objekt mit einer "unapply" Methode kann per Pattern geprüft werden
|
||||
// Ganze Funktionen können Patterns sein
|
||||
```
|
||||
val patternFunc: Person => String = {
|
||||
case Person("George", number) => s"George's number: $number"
|
||||
case Person(name, number) => s"Random person's number: $number"
|
||||
}
|
||||
```
|
||||
|
||||
# 7. Higher-order functions
|
||||
Scala erlaubt, das Methoden und Funktion wiederum Funtionen und Methoden
|
||||
als Aufrufparameter oder Return Wert verwenden. Diese Methoden heissen
|
||||
higher-order functions
|
||||
Es gibt zahlreiche higher-order functions nicht nur für Listen, auch für
|
||||
die meisten anderen Collection Typen, sowie andere Klassen in Scala
|
||||
Nennenswerte sind:
|
||||
"filter", "map", "reduce", "foldLeft"/"foldRight", "exists", "forall"
|
||||
|
||||
## List
|
||||
```
|
||||
def isGleichVier(a:Int) = a == 4
|
||||
val list = List(1, 2, 3, 4)
|
||||
val resultExists4 = list.exists(isEqualToFour)
|
||||
```
|
||||
|
||||
## map
|
||||
// map nimmt eine Funktion und führt sie auf jedem Element aus und erzeugt
|
||||
// eine neue Liste
|
||||
|
||||
// Funktion erwartet ein Int und returned ein Int
|
||||
```
|
||||
val add10: Int => Int = _ + 10
|
||||
```
|
||||
|
||||
// add10 wird auf jedes Element angewendet
|
||||
```
|
||||
List(1, 2, 3) map add10 // => List(11, 12, 13)
|
||||
```
|
||||
|
||||
// Anonyme Funktionen können anstatt definierter Funktionen verwendet werden
|
||||
```
|
||||
List(1, 2, 3) map (x => x + 10)
|
||||
```
|
||||
|
||||
// Der Unterstrich wird anstelle eines Parameters einer anonymen Funktion
|
||||
// verwendet. Er wird an die Variable gebunden.
|
||||
```
|
||||
List(1, 2, 3) map (_ + 10)
|
||||
```
|
||||
|
||||
// Wenn der anonyme Block und die Funtion beide EIN Argument erwarten,
|
||||
// kann sogar der Unterstrich weggelassen werden.
|
||||
```
|
||||
List("Dom", "Bob", "Natalia") foreach println
|
||||
```
|
||||
|
||||
## filter
|
||||
// filter nimmt ein Prädikat (eine Funktion von A -> Boolean) und findet
|
||||
// alle Elemente die auf das Prädikat passen
|
||||
```
|
||||
List(1, 2, 3) filter (_ > 2) // => List(3)
|
||||
case class Person(name: String, age: Int)
|
||||
List(
|
||||
Person(name = "Dom", age = 23),
|
||||
Person(name = "Bob", age = 30)
|
||||
).filter(_.age > 25) // List(Person("Bob", 30))
|
||||
```
|
||||
|
||||
## reduce
|
||||
// reduce nimmt zwei Elemente und kombiniert sie zu einem Element,
|
||||
// und zwar solange bis nur noch ein Element da ist.
|
||||
|
||||
## foreach
|
||||
// foreach gibt es für einige Collections
|
||||
```
|
||||
val aListOfNumbers = List(1, 2, 3, 4, 10, 20, 100)
|
||||
aListOfNumbers foreach (x => println(x))
|
||||
aListOfNumbers foreach println
|
||||
```
|
||||
## For comprehensions
|
||||
// Eine for-comprehension definiert eine Beziehung zwischen zwei Datensets.
|
||||
// Dies ist keine for-Schleife.
|
||||
```
|
||||
for { n <- s } yield sq(n)
|
||||
val nSquared2 = for { n <- s } yield sq(n)
|
||||
for { n <- nSquared2 if n < 10 } yield n
|
||||
for { n <- s; nSquared = n * n if nSquared < 10} yield nSquared
|
||||
```
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
# 8. Implicits
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
**ACHTUNG:**
|
||||
Implicits sind ein sehr mächtiges Sprachfeature von Scala. Es sehr einfach
|
||||
sie falsch zu benutzen und Anfänger sollten sie mit Vorsicht oder am
|
||||
besten erst dann benutzen, wenn man versteht wie sie funktionieren.
|
||||
Dieses Tutorial enthält Implicits, da sie in Scala an jeder Stelle
|
||||
vorkommen und man auch mit einer Lib die Implicits benutzt nichts sinnvolles
|
||||
machen kann.
|
||||
Hier soll ein Grundverständnis geschaffen werden, wie sie funktionieren.
|
||||
|
||||
// Mit dem Schlüsselwort implicit können Methoden, Werte, Funktion, Objekte
|
||||
// zu "implicit Methods" werden.
|
||||
```
|
||||
implicit val myImplicitInt = 100
|
||||
implicit def myImplicitFunction(sorte: String) = new Hund("Golden " + sorte)
|
||||
```
|
||||
|
||||
// implicit ändert nicht das Verhalten eines Wertes oder einer Funktion
|
||||
```
|
||||
myImplicitInt + 2 // => 102
|
||||
myImplicitFunction("Pitbull").sorte // => "Golden Pitbull"
|
||||
```
|
||||
|
||||
// Der Unterschied ist, dass diese Werte ausgewählt werden können, wenn ein
|
||||
// anderer Codeteil einen implicit Wert benötigt, zum Beispiel innerhalb von
|
||||
// implicit Funktionsparametern
|
||||
|
||||
// Diese Funktion hat zwei Parameter: einen normalen und einen implicit
|
||||
```
|
||||
def sendGreetings(toWhom: String)(implicit howMany: Int) =
|
||||
s"Hello $toWhom, $howMany blessings to you and yours!"
|
||||
```
|
||||
|
||||
// Werden beide Parameter gefüllt, verhält sich die Funktion wie erwartet
|
||||
```
|
||||
sendGreetings("John")(1000) // => "Hello John, 1000 blessings to you and yours!"
|
||||
```
|
||||
|
||||
// Wird der implicit Parameter jedoch weggelassen, wird ein anderer
|
||||
// implicit Wert vom gleichen Typ genommen. Der Compiler sucht im
|
||||
// lexikalischen Scope und im companion object nach einem implicit Wert,
|
||||
// der vom Typ passt, oder nach einer implicit Methode mit der er in den
|
||||
// geforderten Typ konvertieren kann.
|
||||
|
||||
// Hier also: "myImplicitInt", da ein Int gesucht wird
|
||||
```
|
||||
sendGreetings("Jane") // => "Hello Jane, 100 blessings to you and yours!"
|
||||
```
|
||||
|
||||
// bzw. "myImplicitFunction"
|
||||
// Der String wird erst mit Hilfe der Funktion in Hund konvertiert, und
|
||||
// dann wird die Methode aufgerufen
|
||||
```
|
||||
"Retriever".sorte // => "Golden Retriever"
|
||||
```
|
||||
|
||||
# 9. Misc
|
||||
## Importe
|
||||
```
|
||||
import scala.collection.immutable.List
|
||||
```
|
||||
|
||||
// Importiere alle Unterpackages
|
||||
```
|
||||
import scala.collection.immutable._
|
||||
```
|
||||
|
||||
// Importiere verschiedene Klassen mit einem Statement
|
||||
```
|
||||
import scala.collection.immutable.{List, Map}
|
||||
```
|
||||
|
||||
// Einen Import kann man mit '=>' umbenennen
|
||||
```
|
||||
import scala.collection.immutable.{List => ImmutableList}
|
||||
```
|
||||
|
||||
// Importiere alle Klasses, mit Ausnahem von....
|
||||
// Hier ohne: Map and Set:
|
||||
```
|
||||
import scala.collection.immutable.{Map => _, Set => _, _}
|
||||
```
|
||||
## Main
|
||||
```
|
||||
object Application {
|
||||
def main(args: Array[String]): Unit = {
|
||||
// stuff goes here.
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## I/O
|
||||
// Eine Datei Zeile für Zeile lesen
|
||||
```
|
||||
import scala.io.Source
|
||||
for(line <- Source.fromFile("myfile.txt").getLines())
|
||||
println(line)
|
||||
```
|
||||
|
||||
// Eine Datei schreiben
|
||||
```
|
||||
val writer = new PrintWriter("myfile.txt")
|
||||
writer.write("Schreibe Zeile" + util.Properties.lineSeparator)
|
||||
writer.write("Und noch eine Zeile" + util.Properties.lineSeparator)
|
||||
writer.close()
|
||||
```
|
||||
|
||||
## Weiterführende Hinweise
|
||||
|
||||
// DE
|
||||
* [Scala Tutorial](https://scalatutorial.wordpress.com)
|
||||
* [Scala Tutorial](http://scalatutorial.de)
|
||||
|
||||
// EN
|
||||
* [Scala for the impatient](http://horstmann.com/scala/)
|
||||
* [Twitter Scala school](http://twitter.github.io/scala_school/)
|
||||
* [The scala documentation](http://docs.scala-lang.org/)
|
||||
* [Try Scala in your browser](http://scalatutorials.com/tour/)
|
||||
* [Neophytes Guide to Scala](http://danielwestheide.com/scala/neophytes.html)
|
||||
* Join the [Scala user group](https://groups.google.com/forum/#!forum/scala-user)
|
Loading…
Reference in New Issue
Block a user