Merge pull request #1556 from coastalchief/master

Scala and Ruby article in german
This commit is contained in:
Adam Bard 2015-10-18 00:33:09 +08:00
commit a125b4a557
3 changed files with 1578 additions and 0 deletions

613
de-de/ruby-de.html.markdown Normal file
View 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.

View 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/)

View 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)