Add German translation of chapter 2

This commit is contained in:
digitalcraftsman
2015-08-07 22:53:30 +02:00
parent 681dfb594c
commit 0441fbce21
9 changed files with 1429 additions and 1412 deletions

View File

@@ -1,307 +1,309 @@
# Object-oriented
# 2.5 Objektorientierte Programmierung
We talked about functions and structs in the last two sections, but did you ever consider using functions as fields of a struct? In this section, I will introduce you to another form of function that has a receiver, which is called `method`.
In den letzen beiden Abschnitten hatten wir uns mit Funktionen und Structs beschäftigt, aber hast Du jemals daran gedacht, Funktionen als Eigenschaft in einem Struct zu verwenden? In diesem Abschnitt werden ich Dir eine besondere Art von Funktionen vorstellen, die einen Reciever (engl. to recieve - empfangen) besitzen. Sie werden auch `Methoden` genannt.
## method
## Methoden
Suppose you define a "rectangle" struct and you want to calculate its area. We'd typically use the following code to achieve this goal.
Sagen wir, Du definierst einen Struct mit dem Namen "Rechteck" und möchtest die Fläche ausrechnen. Normalerweise würden wir folgenden Code verwenden, um dies zu bewerkstelligen.
package main
import "fmt"
package main
import "fmt"
type Rectangle struct {
width, height float64
}
type Rechteck struct {
breite, höhe float64
}
func area(r Rectangle) float64 {
return r.width*r.height
}
func Fläche(r Rechteck) float64 {
return r.breite*r.höhe
}
func main() {
r1 := Rectangle{12, 2}
r2 := Rectangle{9, 4}
fmt.Println("Area of r1 is: ", area(r1))
fmt.Println("Area of r2 is: ", area(r2))
}
The above example can calculate a rectangle's area. We use the function called `area`, but it's not a method of the rectangle struct (like class methods in classic object-oriented languages). The function and struct are two independent things as you may notice.
func main() {
r1 := Rechteck{12, 2}
r2 := Rechteck{9, 4}
fmt.Println("Fläche von r1: ", Fläche(r1))
fmt.Println("Fläche von r2: ", Fläche(r2))
}
Das obere Beispiel kann die Fläche eines Rechtecks ermitteln. Dafür haben wir die Funktion `Fläche()` verwendet, aber es ist keine Methode des Structs Rechteck (welche mit einer Klasse in klassischen objektorientierten Sprachen wären). Die Funktion und der Struct sind voneinander unabhängig.
It's not a problem so far. However, if you also have to calculate the area of a circle, square, pentagon, or any other kind of shape, you are going to need to add additional functions with very similar names.
Soweit ist dies noch kein Problem. Wenn Du aber den Flächeninhalt eines Kreies, Quadrahts, Fünfecks oder einer anderen Form berechnen musst, brauchst Du dafür Funktionen mit einem sehr ähnlichen Namen,
![](images/2.5.rect_func_without_receiver.png?raw=true)
Figure 2.8 Relationship between function and struct
Abbildung 2.8 Beziehung zwischen Funktionen und Structs
Obviously that's not cool. Also, the area should really be the property of a circle or rectangle.
Offensichtlich ist dies nicht sehr praktisch. Auch sollte die Fläche eine Eigenschaft des Kreises oder Rechtecks sein.
For those reasons, we have the `method` concept. `method` is affiliated with type. It has the same syntax as functions do except for an additional parameter after the `func` keyword called the `receiver`, which is the main body of that method.
Aus diesem Grund gibt es das Konzept der `Methoden`. Diese sind immer mit einem Datentyp verbunden. Sie haben den selben Syntax wie normale Funktionen, jedoch besitzen sie einen weiteren Parameter nach dem Schlüsselwort `func`, den `Reciever`.
Using the same example, `Rectangle.area()` belongs directly to rectangle, instead of as a peripheral function. More specifically, `length`, `width` and `area()` all belong to rectangle.
Im selben Beispiel würde mit `Rechteck.Fläche()` die Methode des Structs Rechteck aufgerufen. Somit gehören `länge`, `breite` und `Fläche()` zum Struct.
As Rob Pike said.
Wie Rob Pike sagte:
"A method is a function with an implicit first argument, called a receiver."
Syntax of method.
"A method is a function with an implicit first argument, called a receiver."
"Eine Methode ist eine Funktion mit einem ersten, impliziten Argument, welches Reciever genannt wird."
func (r ReceiverType) funcName(parameters) (results)
Let's change our example using `method` instead.
Syntax einer Methode.
package main
import (
"fmt"
"math"
)
func (r RecieverTyp) funcName(Parameter) (Ergebnis)
Lass uns das Beispiel von vorhin umschreiben.
type Rectangle struct {
width, height float64
}
package main
import (
"fmt"
"math"
)
type Circle struct {
radius float64
}
type Rechteck struct {
breite, höhe float64
}
func (r Rectangle) area() float64 {
return r.width*r.height
}
type Kreis struct {
radius float64
}
func (c Circle) area() float64 {
return c.radius * c.radius * math.Pi
}
func (r Rechteck) fläche() float64 {
return r.breite*r.höhe
}
func main() {
r1 := Rectangle{12, 2}
r2 := Rectangle{9, 4}
c1 := Circle{10}
c2 := Circle{25}
func (c Kreis) fläche() float64 {
return c.radius * c.radius * math.Pi
}
fmt.Println("Area of r1 is: ", r1.area())
fmt.Println("Area of r2 is: ", r2.area())
fmt.Println("Area of c1 is: ", c1.area())
fmt.Println("Area of c2 is: ", c2.area())
}
Notes for using methods.
func main() {
r1 := Rechteck{12, 2}
r2 := Rechteck{9, 4}
c1 := Kreis{10}
c2 := Kreis{25}
- If the name of methods are the same but they don't share the same receivers, they are not the same.
- Methods are able to access fields within receivers.
- Use `.` to call a method in the struct, the same way fields are called.
fmt.Println("Fläche von r1 ist: ", r1.fläche())
fmt.Println("Fläche von r2 ist: ", r2.fläche())
fmt.Println("Fläche von c1 ist: ", c1.fläche())
fmt.Println("Fläche von c2 ist: ", c2.fläche())
}
Anmerkungen zu der Nutzung von Methoden.
- Beide Methoden haben den selben Namen, gehören jedoch verschiedenen Recievern an.
- Methoden können auf die Eigenschaften des Recievers zugreifen.
- Nutze `.`, um Methoden wie Eigenschaften aufzurufen.
![](images/2.5.shapes_func_with_receiver_cp.png?raw=true)
Figure 2.9 Methods are different in different structs
Abbildung 2.9 Die Methoden sind in jedem Struct verschieden
In the example above, the area() methods belong to both Rectangle and Circle respectively, so the receivers are Rectangle and Circle.
Im oberen Beispiel ist die Methode `Fläche()` für Rechteck und Kreis zugänglich, sodass sie zwei verschiedene Reciever besitzt.
One thing that's worth noting is that the method with a dotted line means the receiver is passed by value, not by reference. The difference between them is that a method can change its receiver's values when the receiver is passed by reference, and it gets a copy of the receiver when the receiver is passed by value.
Bei der Nutzung von Methoden werden dieser Kopien der Werte eines Structs übergeben. `Fläche()` bekommt also nicht einen Zeiger zum Original übergeben, sondern nur eine Kopie dessen. Somit kann das Orginal nicht verändert werden. Ein `*` vor dem Reciver übergibt dageben den Zeiger und erlaubt damit auch Zugriff auf das Original.
Can the receiver only be a struct? Of course not. Any type can be the receiver of a method. You may be confused about customized types. Struct is a special kind of customized type -there are more customized types.
Können Reciever nur in Verbindung mit Structs genutzt werden? Natürlich nicht. Jeder Datentyp kann als Reciever fungieren. Dies wird Dir vielleicht bei selbstdefinierten Datentypen etwas komisch vorkommen, aber mit den Structs haben wir das Selbe gemacht - einen eigenen Datentypen erstellt.
Use the following format to define a customized type.
Das Folgende Schema kann genutzt werden, um einen neuen Datentypen zu definieren.
type typeName typeLiteral
Examples of customized types:
type Name Datentyp
Beispiele für selbstdefinierte Datentypen:
type ages int
type alter int
type money float32
type geld float32
type months map[string]int
type monate map[string]int
m := months {
"January":31,
"February":28,
...
"December":31,
}
I hope that you know how to use customized types now. Similar to `typedef` in C, we use `ages` to substitute `int` in the above example.
m := monate {
"Januar":31,
"Februar":28,
...
"Dezember":31,
}
Ich hoffe, dass Du die Definition eigener Datentypen jetzt verstanden hast. Es ist `typedef` aus C sehr ähnlich. Im oberen Beispiel ersetzen wir `int` einfach durch `alter`.
Let's get back to talking about `method`.
Kommen wir zurück zu unseren `Methoden`.
You can use as many methods in custom types as you want.
Du kannst soviele Datentypen und dazugehörige Methoden erstellen, wie Du willst.
package main
import "fmt"
package main
import "fmt"
const(
WHITE = iota
BLACK
BLUE
RED
YELLOW
)
const(
WEISS = iota
SCHWARZ
BLAU
ROT
GELB
)
type Color byte
type Farbe byte
type Box struct {
width, height, depth float64
color Color
}
type Box struct {
breite, höhe, tiefe float64
farbe Farbe
}
type BoxList []Box //a slice of boxes
type BoxListe []Box // Ein Slice mit Elementen vom Typ Box
func (b Box) Volume() float64 {
return b.width * b.height * b.depth
}
func (b Box) Volumen() float64 {
return b.breite * b.höhe * b.tiefe
}
func (b *Box) SetColor(c Color) {
b.color = c
}
func (b *Box) SetzeFarbe(c Farbe) {
b.farbe = c
}
func (bl BoxList) BiggestsColor() Color {
v := 0.00
k := Color(WHITE)
for _, b := range bl {
if b.Volume() > v {
v = b.Volume()
k = b.color
}
}
return k
}
func (bl BoxListe) HöchsteFarbe() Farbe {
v := 0.00
k := Farbe(WEISS)
for _, b := range bl {
if b.Volumen() > v {
v = b.Volumen()
k = b.farbe
}
}
return k
}
func (bl BoxList) PaintItBlack() {
for i, _ := range bl {
bl[i].SetColor(BLACK)
}
}
func (bl BoxListe) MaleAlleSchwarzAn() {
for i, _ := range bl {
bl[i].SetzeFarbe(SCHWARZ)
}
}
func (c Color) String() string {
strings := []string {"WHITE", "BLACK", "BLUE", "RED", "YELLOW"}
return strings[c]
}
func (c Farbe) String() string {
strings := []string {"WEISS", "SCHWARZ", "BLAU", "ROT", "GELB"}
return strings[c]
}
func main() {
boxes := BoxList {
Box{4, 4, 4, RED},
Box{10, 10, 1, YELLOW},
Box{1, 1, 20, BLACK},
Box{10, 10, 1, BLUE},
Box{10, 30, 1, WHITE},
Box{20, 20, 20, YELLOW},
}
func main() {
boxes := BoxListe {
Box{4, 4, 4, ROT},
Box{10, 10, 1, GELB},
Box{1, 1, 20, SCHWARZ},
Box{10, 10, 1, BLAU},
Box{10, 30, 1, WEISS},
Box{20, 20, 20, GELB},
}
fmt.Printf("We have %d boxes in our set\n", len(boxes))
fmt.Println("The volume of the first one is", boxes[0].Volume(), "cm³")
fmt.Println("The color of the last one is",boxes[len(boxes)-1].color.String())
fmt.Println("The biggest one is", boxes.BiggestsColor().String())
fmt.Printf("Wir haben %d Boxen in unserer Liste\n", len(boxes))
fmt.Println("Das Volumen der Ersten beträgt ", boxes[0].Volumen(), "cm³")
fmt.Println("Die Farbe der letzen Box ist",boxes[len(boxes)-1].farbe.String())
fmt.Println("Die größte Box ist ", boxes.HöchsteFarbe().String())
fmt.Println("Let's paint them all black")
boxes.PaintItBlack()
fmt.Println("The color of the second one is", boxes[1].color.String())
fmt.Println("Malen wir sie alle schwarz an")
boxes.MaleAlleSchwarzAn()
fmt.Println("Die Farbe der zweiten Box lautet ", boxes[1].farbe.String())
fmt.Println("Obviously, now, the biggest one is", boxes.BiggestsColor().String())
}
We define some constants and customized types.
fmt.Println("Offensichtlich ist die größte Box ", boxes.HöchsteFarbe().String())
}
Wir hatten ein paar Konstanten und selbstdefinierte Datentypen erstellt.
- Use `Color` as alias of `byte`.
- Define a struct `Box` which has fields height, width, length and color.
- Define a struct `BoxList` which has `Box` as its field.
- Nutze `Farbe` als Alias für `byte`.
- Wir definierten den Struct `Box` mit den Eigenschaften breite, länge, tiefe und farbe.
- Wir definierten einen Slice `BoxListe` mit Elementen vom Typ `Box`.
Then we defined some methods for our customized types.
Dann haben wir Methoden für unsere selbsterstellten Datentypen hinzugefügt.
- Volume() uses Box as its receiver and returns volume of Box.
- SetColor(c Color) changes Box's color.
- BiggestsColor() returns the color which has the biggest volume.
- PaintItBlack() sets color for all Box in BoxList to black.
- String() use Color as its receiver, returns the string format of color name.
- Volumen() nutzt Box als Reciever und gibt das Volumen einer Box.
- SetzeFarbe(c Farbe) ändert die Farbe einer Box.
- GrößteFarbe() gibt die Box mit dem größten Volumen zurück.
- MaleAlleSchwarzAn() setzt die Farbe aller Boxen auf schwarz.
- String() benutzt Farbe als Reciever und gibt den Farbnamen als String zurück.
Is it much clearer when we use words to describe our requirements? We often write our requirements before we start coding.
Ist es nicht einfacher, Wörter zum Beschreiben unserer Anforderungen zu benutzen? Oftmals definieren wir unsere Anforderungen schon vor dem Programmieren.
### Use pointer as receiver
### Zeiger als Reciever
Let's take a look at `SetColor` method. Its receiver is a pointer of Box. Yes, you can use `*Box` as a receiver. Why do we use a pointer here? Because we want to change Box's color in this method. Thus, if we don't use a pointer, it will only change the value inside a copy of Box.
Werfen wir einen näheren Blick auf die Methode `SetzeFarbe()`. Ihr Reciever ist der Zeiger mit dem Verweis zu einer Box. Warum benutzen wir hier einen Zeiger? Wie bereits erwähnt, erhälst Du mit `*Box` Zugriff auf das Original und kannst es somit ändern. Nützten wir keinen Zeiger, so hätte die Methode nur eine Kopie des Wertes übergeben bekommen.
If we see that a receiver is the first argument of a method, it's not hard to understand how it works.
Wenn wir einen Reciever als ersten Parameter einer Methode sehen, dürfte ihr Zweck leicht zu verstehen sein.
You might be asking why we aren't using `(*b).Color=c` instead of `b.Color=c` in the SetColor() method. Either one is OK here because Go knows how to interpret the assignment. Do you think Go is more fascinating now?
Du fragst Dich bestimmt, warum wir nicht einfach `(*b).Farbe=c` verwenden, statt `b.Color=c` in der `SetzeFarbe()` Methode. Beide Wege sind OK und Go weiß die erste Zuweisung zu interpretieren. Findest Du Go nun nicht auch faszinierend?
You may also be asking whether we should use `(&bl[i]).SetColor(BLACK)` in `PaintItBlack` because we pass a pointer to `SetColor`. Again, either one is OK because Go knows how to interpret it!
Des Weiteren fragst Du dich vielleicht auch, warum wir nicht `(&bl[i]).SetzeFarbe(BLACK)` in `MaleAlleSchwarzAn()` nutzen, so wie es in `SetzeFarbe()` der Fall ist. Nochmals, beide Varianten sind OK und Go weiß damit umzugehen.
### Inheritance of method
### Vererbung von Methoden
We learned about inheritance of fields in the last section. Similarly, we also have method inheritance in Go. If an anonymous field has methods, then the struct that contains the field will have all the methods from it as well.
Wir haben die Vererbung bzw. das Einbetten von Eigengeschaften bereits im letzen Abschnitt kennengelernt. Ähnlich funktioniert auch das Einbetten von Methoden. Wenn ein Struct eigene Methoden hat und es in ein weiteres Struct eingebettet wird, so werden die Methoden wie die Eigenschaften mit eingebettet, also vererbt.
package main
import "fmt"
package main
import "fmt"
type Human struct {
name string
age int
phone string
}
type Mensch struct {
name string
alter int
telefon string
}
type Student struct {
Human // anonymous field
school string
}
type Student struct {
Mensch // Eingebetter Struct als Eigenschaft ohne Namen
schule string
}
type Employee struct {
Human
company string
}
type Mitarbeiter struct {
Mensch
unternehmen string
}
// define a method in Human
func (h *Human) SayHi() {
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}
// Definiere eine Methode für Mensch
func (h *Mensch) SagHallo() {
fmt.Printf("Hallo, ich bin %s. Du erreichst mich unter %s\n", h.name, h.telefon)
}
func main() {
mark := Student{Human{"Mark", 25, "222-222-YYYY"}, "MIT"}
sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "Golang Inc"}
func main() {
mark := Student{Mensch{"Mark", 25, "222-222-YYYY"}, "MIT"}
sam := Mitarbeiter{Mensch{"Sam", 45, "111-888-XXXX"}, "Golang Inc"}
mark.SayHi()
sam.SayHi()
}
mark.SagHallo()
sam.SagHallo()
}
### Method overload
### Das Überladen von Methoden
If we want Employee to have its own method `SayHi`, we can define a method that has the same name in Employee, and it will hide `SayHi` in Human when we call it.
Wenn wir für Mitarbeiter eine eigene Methode `SagHallo()` erstellen wollen, wird die Methode `SagHallo()` von Mensch durch die von Mitarbeiter überladen.
package main
import "fmt"
package main
import "fmt"
type Human struct {
name string
age int
phone string
}
type Mensch struct {
name string
alter int
telefon string
}
type Student struct {
Human
school string
}
type Student struct {
Mensch
schule string
}
type Employee struct {
Human
company string
}
type Mitarbeiter struct {
Mensch
unternehmen string
}
func (h *Human) SayHi() {
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}
func (h *Mensch) SagHallo() {
fmt.Printf("Hallo, ich bin %s und Du erreicht mich unter %s\n", h.name, h.telefon)
}
func (e *Employee) SayHi() {
fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,
e.company, e.phone) //Yes you can split into 2 lines here.
}
func (e *Mitarbeiter) SagHallo() {
fmt.Printf("Hallo, ich bin %s, arbeite bei %s. Du erreicht mich unter %s\n", e.name,
e.unternehmen, e.telefon) // Du kannst die Argumente auch auf zwei Zeilen verteilen.
}
func main() {
mark := Student{Human{"Mark", 25, "222-222-YYYY"}, "MIT"}
sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "Golang Inc"}
func main() {
mark := Student{Mensch{"Mark", 25, "222-222-YYYY"}, "MIT"}
sam := Mitarbeiter{Mensch{"Sam", 45, "111-888-XXXX"}, "Golang Inc"}
mark.SayHi()
sam.SayHi()
}
You are able to write an Object-oriented program now, and methods use rule of capital letter to decide whether public or private as well.
mark.SagHallo()
sam.SagHallo()
}
Nun bist Du bereit, Dein eigenes, objektorientiers Programm zu schreiben. Auch Methoden unterliegen der Regel, dass die Groß- und Kleinschreibung des ersten Buchstaben über die Sichtbarkeit (öffentlich oder privat) entscheidet.
## Links
- [Directory](preface.md)
- Previous section: [struct](02.4.md)
- Next section: [interface](02.6.md)
- [Inhaltsverzeichnis](preface.md)
- Vorheriger Abschnitt: [Struct](02.4.md)
- Nächster Abschnitt: [Interface](02.6.md)