Add German translation of chapter 2
This commit is contained in:
370
de/02.6.md
370
de/02.6.md
@@ -1,199 +1,199 @@
|
||||
# 2.6 Interface
|
||||
# 2.6 Interfaces
|
||||
|
||||
## Interface
|
||||
|
||||
One of the subtlest design features in Go are interfaces. After reading this section, you will likely be impressed by their implementation.
|
||||
Eines der besten Sprachmerkmale von Go sind Interfaces. Nach dem Lesen dieses Abschnitts wirst Du über dessen Implementation staunen.
|
||||
|
||||
### What is an interface
|
||||
### Was ist ein Interface
|
||||
|
||||
In short, an interface is a set of methods that we use to define a set of actions.
|
||||
Kurz gesagt, ein Interface dient der Zusammenfassung von Funktionen, die durch ihren ähnlichen Aufbau eine Beziehung zueinander haben.
|
||||
|
||||
Like the examples in previous sections, both Student and Employee can `SayHi()`, but they don't do the same thing.
|
||||
Wie im Beispiel aus dem letzten Abschnitt haben Student und Mitarbeiter hier beide die Methode `SagHallo()`, welche sich ähnlich, aber nicht gleich verhalten.
|
||||
|
||||
Let's do some more work. We'll add one more method `Sing()` to them, along with the `BorrowMoney()` method to Student and the `SpendSalary()` method to Employee.
|
||||
Machen wir uns wieder an die Arbeit, indem wir beiden Structs die Methode `Singen()` hinzufügen. Zudem erweitern wir Student um die Methode `GeldLeihen()` und Mitarbeiter um die Methode `GehaltAusgeben()`.
|
||||
|
||||
Now, Student has three methods called `SayHi()`, `Sing()` and `BorrowMoney()`, and Employee has `SayHi()`, `Sing()` and `SpendSalary()`.
|
||||
Nun besitzt Student die drei Methoden `SagHallo()`, `Singen()` und `GeldLeihen()` und Mitarbeiter `SagHallo()`, `Singen()` sowie `GehaltAusgeben()`.
|
||||
|
||||
This combination of methods is called an interface and is implemented by both Student and Employee. So, Student and Employee implement the interface: `SayHi()` and `Sing()`. At the same time, Employee doesn't implement the interface: `SayHi()`, `Sing()`, `BorrowMoney()`, and Student doesn't implement the interface: `SayHi()`, `Sing()`, `SpendSalary()`. This is because Employee doesn't have the method `BorrowMoney()` and Student doesn't have the method `SpendSalary()`.
|
||||
Diese Kombination von Methoden wird Interface genannt und umfasst sowohl Student als auch Mitarbeiter. Somit besitzen beide Datentypen die Interfaces `SagHallo()` und `Singen()`. Jedoch implementieren beide Datentypen keine gemeinsames Interfaces für `GeldLeihen()` und `GehaltAusgeben()`, da diese Methoden nicht für beide Structs definiert wurden.
|
||||
|
||||
### Type of Interface
|
||||
### Interface als Datentyp
|
||||
|
||||
An interface defines a set of methods, so if a type implements all the methods we say that it implements the interface.
|
||||
Ein Interface definiert eine Liste von Methoden. Besitzt ein Datentyp alle Methoden, die das Interface definiert, so umfasst das Interface diesen Datentypen. Schauen wir uns ein Beispiel zur Verdeutlichung an.
|
||||
|
||||
type Human struct {
|
||||
name string
|
||||
age int
|
||||
phone string
|
||||
type Mensch struct {
|
||||
name string
|
||||
alter int
|
||||
telefon string
|
||||
}
|
||||
|
||||
type Student struct {
|
||||
Human
|
||||
school string
|
||||
loan float32
|
||||
Mensch
|
||||
schule string
|
||||
kredit float32
|
||||
}
|
||||
|
||||
type Employee struct {
|
||||
Human
|
||||
company string
|
||||
money float32
|
||||
type Mitarbeiter struct {
|
||||
Mensch
|
||||
unternehmen string
|
||||
geld float32
|
||||
}
|
||||
|
||||
func (h *Human) SayHi() {
|
||||
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
|
||||
func (m *Mensch) SagHallo() {
|
||||
fmt.Printf("Hallo, ich bin %s und Du erreichst mich unter %s\n", m.name, m.telefon)
|
||||
}
|
||||
|
||||
func (h *Human) Sing(lyrics string) {
|
||||
fmt.Println("La la, la la la, la la la la la...", lyrics)
|
||||
func (m *Mensch) Singen(liedtext string) {
|
||||
fmt.Println("La la, la la la, la la la la la...", liedtext)
|
||||
}
|
||||
|
||||
func (h *Human) Guzzle(beerStein string) {
|
||||
fmt.Println("Guzzle Guzzle Guzzle...", beerStein)
|
||||
func (m *Mensch) SichBetrinken(bierkrug string) {
|
||||
fmt.Println("schluck schluck schluck...", bierkrug)
|
||||
}
|
||||
|
||||
// Employee overloads Sayhi
|
||||
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.
|
||||
// Mitarbeiter "überlädt" SagHallo
|
||||
func (m *Mitarbeiter) SagHallo() {
|
||||
fmt.Printf("Hallo, ich bin %s und arbeite bei %s. Ruf mich unter der Nummer %s an\n", m.name,
|
||||
m.unternehmen, m.telefon) // Du kannst die Argumente auch auf zwei Zweilen aufteilen.
|
||||
}
|
||||
|
||||
func (s *Student) BorrowMoney(amount float32) {
|
||||
s.loan += amount // (again and again and...)
|
||||
func (s *Student) GeldLeihen(betrag float32) {
|
||||
s.kredit += betrag // (immer und immer wieder...)
|
||||
}
|
||||
|
||||
func (e *Employee) SpendSalary(amount float32) {
|
||||
e.money -= amount // More vodka please!!! Get me through the day!
|
||||
func (m *Mitarbeiter) GehaltAusgeben(betrag float32) {
|
||||
m.geld -= betrag // Einen Vodka bitte!!! Bring mich durch den Tag!
|
||||
}
|
||||
|
||||
// define interface
|
||||
type Men interface {
|
||||
SayHi()
|
||||
Sing(lyrics string)
|
||||
Guzzle(beerStein string)
|
||||
// Das Interface definieren
|
||||
type Männer interface {
|
||||
SagHallo()
|
||||
Singe(liedtext string)
|
||||
SichBetrinken(bierkrug string)
|
||||
}
|
||||
|
||||
type YoungChap interface {
|
||||
SayHi()
|
||||
Sing(song string)
|
||||
BorrowMoney(amount float32)
|
||||
type JungerMann interface {
|
||||
SagHallo()
|
||||
Singe(liedtext string)
|
||||
GeldLeihen(betrag float32)
|
||||
}
|
||||
|
||||
type ElderlyGent interface {
|
||||
SayHi()
|
||||
Sing(song string)
|
||||
SpendSalary(amount float32)
|
||||
type Greis interface {
|
||||
SagHallo()
|
||||
Singe(liedtext string)
|
||||
GeldAusgeben(betrag float32)
|
||||
}
|
||||
|
||||
We know that an interface can be implemented by any type, and one type can implement many interfaces simultaneously.
|
||||
Wir wissen, dass ein Interface von jedem Datentypen implementiert werden und ein Datentyp viele Interfaces umfassen kann.
|
||||
|
||||
Note that any type implements the empty interface `interface{}` because it doesn't have any methods and all types have zero methods by default.
|
||||
Zudem implementiert jeder Datentyp das leere Interface `interface{}`, da es keine Methoden definiert und alle Datentypen von Beginn an keine Methoden besitzen.
|
||||
|
||||
### Value of interface
|
||||
### Interface als Datentyp
|
||||
|
||||
So what kind of values can be put in the interface? If we define a variable as a type interface, any type that implements the interface can assigned to this variable.
|
||||
Welche Arten von Werten können mit einem Interface verknüpft werden? Wen wir eine Variable vom Typ Interface definieren, dann kann jeder Datentyp, der das Interface implementiert wird, der Variable zugewiesen werden.
|
||||
|
||||
Like the above example, if we define a variable "m" as interface Men, then any one of Student, Human or Employee can be assigned to "m". So we could have a slice of Men, and any type that implements interface Men can assign to this slice. Be aware however that the slice of interface doesn't have the same behavior as a slice of other types.
|
||||
Es ist wie im oberen Beispiel. Erstellen wir eine Variable "m" mit dem Interface Männer, kann jeder Student, Mensch oder Mitarbeiter "m" zugewiesen werden. So könnten wir ein Slice mit dem Interface Männer jeden Datentyp hinzufügen, der ebenfalls das Interface Männer implementiert. Bedenke aber, dass sich das Verhalten von Slices ändert, wenn dies Elemente eines Interface statt eines Datentypes verwendet.
|
||||
|
||||
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
|
||||
loan float32
|
||||
Mensch
|
||||
schule string
|
||||
geld float32
|
||||
}
|
||||
|
||||
type Employee struct {
|
||||
Human
|
||||
company string
|
||||
money float32
|
||||
type Mitarbeiter struct {
|
||||
Mensch
|
||||
unternehmen string
|
||||
geld float32
|
||||
}
|
||||
|
||||
func (h Human) SayHi() {
|
||||
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
|
||||
func (m Mensch) SagHallo() {
|
||||
fmt.Printf("Hallo, ich bin %s und Du erreicht mich unter %s\n", m.name, m.telefon)
|
||||
}
|
||||
|
||||
func (h Human) Sing(lyrics string) {
|
||||
fmt.Println("La la la la...", lyrics)
|
||||
func (m Mensch) Singe(liedtext string) {
|
||||
fmt.Println("La la la la...", liedtext)
|
||||
}
|
||||
|
||||
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 (m Mitarbeiter) SagHallo() {
|
||||
fmt.Printf("Hallo, ich bin %s und arbeite bei %s. Rufe mich unter der Nummer %s an\n", m.name,
|
||||
m.unternehmen, m.telefon) // Du kannst die Argumente auch auf zwei Zweilen aufteilen.
|
||||
}
|
||||
|
||||
// Interface Men implemented by Human, Student and Employee
|
||||
type Men interface {
|
||||
SayHi()
|
||||
Sing(lyrics string)
|
||||
// Das Interface Männer wird von Mensch, Student und Mitarbeiter implementiert
|
||||
type Männer interface {
|
||||
SagHallo()
|
||||
Singe(liedtext string)
|
||||
}
|
||||
|
||||
func main() {
|
||||
mike := Student{Human{"Mike", 25, "222-222-XXX"}, "MIT", 0.00}
|
||||
paul := Student{Human{"Paul", 26, "111-222-XXX"}, "Harvard", 100}
|
||||
sam := Employee{Human{"Sam", 36, "444-222-XXX"}, "Golang Inc.", 1000}
|
||||
Tom := Employee{Human{"Sam", 36, "444-222-XXX"}, "Things Ltd.", 5000}
|
||||
mike := Student{Mensch{"Mike", 25, "222-222-XXX"}, "MIT", 0.00}
|
||||
paul := Student{Mensch{"Paul", 26, "111-222-XXX"}, "Harvard", 100}
|
||||
sam := Mitarbeiter{Mensch{"Sam", 36, "444-222-XXX"}, "Golang Inc.", 1000}
|
||||
Tom := Mitarbeiter{Mensch{"Sam", 36, "444-222-XXX"}, "Things Ltd.", 5000}
|
||||
|
||||
// define interface i
|
||||
var i Men
|
||||
// Definiere i vom Typ Interface Männer
|
||||
var i Männer
|
||||
|
||||
//i can store Student
|
||||
// i kann Studenten zugewiesen bekommen
|
||||
i = mike
|
||||
fmt.Println("This is Mike, a Student:")
|
||||
i.SayHi()
|
||||
i.Sing("November rain")
|
||||
fmt.Println("Das ist Mike, ein Student:")
|
||||
i.SagHallo()
|
||||
i.Singe("November rain")
|
||||
|
||||
//i can store Employee
|
||||
// i kann auch Mitarbeiter zugewiesen bekommen
|
||||
i = Tom
|
||||
fmt.Println("This is Tom, an Employee:")
|
||||
i.SayHi()
|
||||
i.Sing("Born to be wild")
|
||||
fmt.Println("Das ist Tom, ein Mitarbeiter:")
|
||||
i.SagHallo()
|
||||
i.Singe("Born to be wild")
|
||||
|
||||
// slice of Men
|
||||
fmt.Println("Let's use a slice of Men and see what happens")
|
||||
x := make([]Men, 3)
|
||||
// these three elements are different types but they all implemented interface Men
|
||||
// Slice mit Männern
|
||||
fmt.Println("Nutzen wir einen Slice vom Typ Männer und schauen, was passiert")
|
||||
x := make([]Männer, 3)
|
||||
// Alle drei Variablen haben verschiedene Datentypen, implentieren aber das selbe Interface
|
||||
x[0], x[1], x[2] = paul, sam, mike
|
||||
|
||||
for _, value := range x {
|
||||
value.SayHi()
|
||||
for _, wert := range x {
|
||||
wert.SagHallo()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
An interface is a set of abstract methods, and can be implemented by non-interface types. It cannot therefore implement itself.
|
||||
Ein Interface ist eine Ansammlung von abstrakten Methoden, das jeder Datentypen implementieren kann, die noch nicht Teil des Interfaces sind. Daher kann es sich nicht selbst implemetieren
|
||||
|
||||
### Empty interface
|
||||
### Leeres Interface
|
||||
|
||||
An empty interface is an interface that doesn't contain any methods, so all types implement an empty interface. This fact is very useful when we want to store all types at some point, and is similar to void* in C.
|
||||
Ein leeres Interfaces umfasst keine Methoden, sodass alle Datentypen dieses Interface implementieren. Dies ist sehr nützlich, wenn wir irgendwann alle Datentypen speichern möchten. Es ist void* aus C sehr ähnlich.
|
||||
|
||||
// define a as empty interface
|
||||
// Definition eines leeren Interfaces
|
||||
var a interface{}
|
||||
var i int = 5
|
||||
s := "Hello world"
|
||||
// a can store value of any type
|
||||
s := "Hallo Welt"
|
||||
// a kann jeder Datentyp zugewiesen werden
|
||||
a = i
|
||||
a = s
|
||||
|
||||
If a function uses an empty interface as its argument type, it can accept any type; if a function uses empty interface as its return value type, it can return any type.
|
||||
Wenn eine Funktion ein leeres Interface als Argumenttyp verwendet, wird jeder Datentyp akzeptiert. Gleiches gilt für den Rückgabewert einer Funktion.
|
||||
|
||||
### Method arguments of an interface
|
||||
### Ein Interface als Methodenargument
|
||||
|
||||
Any variable can be used in an interface. So how can we use this feature to pass any type of variable to a function?
|
||||
Jede Variable kann mit einem Interface genutzt werden. Aber wie können wir diese Eigenschaft nutzen, um einen beliebigen Datentyp einer Funktion zu übergeben?
|
||||
|
||||
For example we use fmt.Println a lot, but have you ever noticed that it can accept any type of argument? Looking at the open source code of fmt, we see the following definition.
|
||||
Zum Beispiel nutzen wir `fmt.Println` sehr oft, aber hast Du jemals gemerkt, dass jeder Datentyp verwendet werden kann? Werfen wir mal einen Blick auf den open-source Code von `fmt`. Wir sehen die folgende Definition der Funktion.
|
||||
|
||||
type Stringer interface {
|
||||
String() string
|
||||
}
|
||||
|
||||
This means any type that implements interface Stringer can be passed to fmt.Println as an argument. Let's prove it.
|
||||
Dies bedeutet, dass jeder Datentyp, der das Interface Stringer implementiert, `fmt.Println` übergeben werden kann. Beweisen wir es.
|
||||
|
||||
package main
|
||||
|
||||
@@ -202,41 +202,42 @@ This means any type that implements interface Stringer can be passed to fmt.Prin
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Human struct {
|
||||
name string
|
||||
age int
|
||||
phone string
|
||||
type Mensch struct {
|
||||
name string
|
||||
alter int
|
||||
telefon string
|
||||
}
|
||||
|
||||
// Human implemented fmt.Stringer
|
||||
func (h Human) String() string {
|
||||
return "Name:" + h.name + ", Age:" + strconv.Itoa(h.age) + " years, Contact:" + h.phone
|
||||
// Mensch implementiert fmt.Stringer
|
||||
func (m Mensch) String() string {
|
||||
return "Name:" + m.name + ", Alter:" + strconv.Itoa(m.alter) + " Jahre, Kontakt:" + m.telefon
|
||||
}
|
||||
|
||||
func main() {
|
||||
Bob := Human{"Bob", 39, "000-7777-XXX"}
|
||||
fmt.Println("This Human is : ", Bob)
|
||||
Bob := Mensch{"Bob", 39, "000-7777-XXX"}
|
||||
fmt.Println("Dieser Mensch ist: ", Bob)
|
||||
}
|
||||
|
||||
|
||||
Looking back to the example of Box, you will find that Color implements interface Stringer as well, so we are able to customize the print format. If we don't implement this interface, fmt.Println prints the type with its default format.
|
||||
Werfen wir nochmal einen Blick auf das Beispiel mit den Boxen von vorhin. Du wirst feststellen, dass der Datentyp Farbe ebenfalls das Interface Stringer definiert, sodass wir die Ausgabe formatieren können. Würden wir dies nicht tun, nutzt `fmt.Println()` die Standardformatierung.
|
||||
|
||||
fmt.Println("The biggest one is", boxes.BiggestsColor().String())
|
||||
fmt.Println("The biggest one is", boxes.BiggestsColor())
|
||||
fmt.Println("Die größte Box ist", boxen.HöchsteFarbe().String())
|
||||
fmt.Println("Die größte Box ist", boxen.HöchsteFarbe())
|
||||
|
||||
Attention: If the type implemented the interface `error`, fmt will call `error()`, so you don't have to implement Stringer at this point.
|
||||
|
||||
### Type of variable in an interface
|
||||
Achtung: Wenn Du das Interface `error` implementierst, wird `fmt` `error()` ausrufen, sodass Du ab hier Stringer noch nicht definieren brauchst.
|
||||
|
||||
If a variable is the type that implements an interface, we know that any other type that implements the same interface can be assigned to this variable. The question is how can we know the specific type stored in the interface. There are two ways which I will show you.
|
||||
### Datentyp eines Interfaces bestimmen
|
||||
|
||||
- Assertion of Comma-ok pattern
|
||||
Wir wissen, dass einer Variable jeder Datentyp zugewiesen werden kann, der ein Interface mit dem originalen Datentypen teilt. Nun stellt sich die Frage, wie wir den genauen Datentypen einer Variable bestimmen können. Hierfür gibt es zwei Wege, die ich Dir zeigen möchte.
|
||||
|
||||
Go has the syntax `value, ok := element.(T)`. This checks to see if the variable is the type that we expect, where "value" is the value of the variable, "ok" is a variable of boolean type, "element" is the interface variable and the T is the type of assertion.
|
||||
- Überprüfung nach dem Komma-ok-Muster
|
||||
|
||||
If the element is the type that we expect, ok will be true, false otherwise.
|
||||
Der in Go übliche Syntax lautet `value, ok := element.(T)`. Er überprüft, ob eine Variable vom erwarteten Datentypen ist. "value" ist der Wert der Variable,"ok" ist vom Typ Boolean, "element" ist eine Interfacevariable und T der zu überprüfende Datentyp.
|
||||
|
||||
Let's use an example to see more clearly.
|
||||
Wenn das Element dem erwarteten Datentypen entspricht, wird ok auf true gesetzt. Anderfalls ist er false.
|
||||
|
||||
Veranschaulichen wir dies anhand eines Beispiels.
|
||||
|
||||
package main
|
||||
|
||||
@@ -246,41 +247,41 @@ Let's use an example to see more clearly.
|
||||
)
|
||||
|
||||
type Element interface{}
|
||||
type List []Element
|
||||
type Liste []Element
|
||||
|
||||
type Person struct {
|
||||
name string
|
||||
age int
|
||||
name string
|
||||
alter int
|
||||
}
|
||||
|
||||
func (p Person) String() string {
|
||||
return "(name: " + p.name + " - age: " + strconv.Itoa(p.age) + " years)"
|
||||
return "(Name: " + p.name + " - Alter: " + strconv.Itoa(p.alter) + " Jahre)"
|
||||
}
|
||||
|
||||
func main() {
|
||||
list := make(List, 3)
|
||||
list[0] = 1 // an int
|
||||
list[1] = "Hello" // a string
|
||||
list[2] = Person{"Dennis", 70}
|
||||
liste := make(Liste, 3)
|
||||
liste[0] = 1 // ein Integer
|
||||
liste[1] = "Hallo" // ein String
|
||||
liste[2] = Person{"Dennis", 70}
|
||||
|
||||
for index, element := range list {
|
||||
for index, element := range liste {
|
||||
if value, ok := element.(int); ok {
|
||||
fmt.Printf("list[%d] is an int and its value is %d\n", index, value)
|
||||
fmt.Printf("liste[%d] ist ein Integer mit dem Wert %d\n", index, value)
|
||||
} else if value, ok := element.(string); ok {
|
||||
fmt.Printf("list[%d] is a string and its value is %s\n", index, value)
|
||||
fmt.Printf("liste[%d] ist ein String mit dem Wert %s\n", index, value)
|
||||
} else if value, ok := element.(Person); ok {
|
||||
fmt.Printf("list[%d] is a Person and its value is %s\n", index, value)
|
||||
fmt.Printf("liste[%d] ist eine Person mit dem Wert %s\n", index, value)
|
||||
} else {
|
||||
fmt.Printf("list[%d] is of a different type\n", index)
|
||||
fmt.Printf("liste[%d] hat einen anderen Datentyp\n", index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
It's quite easy to use this pattern, but if we have many types to test, we'd better use `switch`.
|
||||
Dieses Muster ist sehr einfach anzuwenden, aber wenn wir viele Datentypen zu bestimmen haben, sollten wir besser `switch` benutzen.
|
||||
|
||||
- switch test
|
||||
- Überprüfung mit switch
|
||||
|
||||
Let's use `switch` to rewrite the above example.
|
||||
Machen wir von `switch` gebrauch und schreiben unser Beispiel um.
|
||||
|
||||
package main
|
||||
|
||||
@@ -290,65 +291,64 @@ Let's use `switch` to rewrite the above example.
|
||||
)
|
||||
|
||||
type Element interface{}
|
||||
type List []Element
|
||||
type Liste []Element
|
||||
|
||||
type Person struct {
|
||||
name string
|
||||
age int
|
||||
name string
|
||||
alter int
|
||||
}
|
||||
|
||||
func (p Person) String() string {
|
||||
return "(name: " + p.name + " - age: " + strconv.Itoa(p.age) + " years)"
|
||||
return "(Name: " + p.name + " - Alter: " + strconv.Itoa(p.alter) + " Jahre)"
|
||||
}
|
||||
|
||||
func main() {
|
||||
list := make(List, 3)
|
||||
list[0] = 1 //an int
|
||||
list[1] = "Hello" //a string
|
||||
list[2] = Person{"Dennis", 70}
|
||||
liste := make(Liste, 3)
|
||||
liste[0] = 1 // Ein Integer
|
||||
liste[1] = "Hello" // Ein String
|
||||
liste[2] = Person{"Dennis", 70}
|
||||
|
||||
for index, element := range list {
|
||||
for index, element := range liste {
|
||||
switch value := element.(type) {
|
||||
case int:
|
||||
fmt.Printf("list[%d] is an int and its value is %d\n", index, value)
|
||||
fmt.Printf("liste[%d] ein Integer mit dem Wert %d\n", index, value)
|
||||
case string:
|
||||
fmt.Printf("list[%d] is a string and its value is %s\n", index, value)
|
||||
fmt.Printf("liste[%d] ist ein String mit dem Wert %s\n", index, value)
|
||||
case Person:
|
||||
fmt.Printf("list[%d] is a Person and its value is %s\n", index, value)
|
||||
fmt.Printf("liste[%d] ist eine Person mit dem Wert %s\n", index, value)
|
||||
default:
|
||||
fmt.Println("list[%d] is of a different type", index)
|
||||
fmt.Println("liste[%d] hat einen anderen Datentyp", index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
One thing you should remember is that `element.(type)` cannot be used outside of the `switch` body, which means in that case you have to use the `comma-ok` pattern .
|
||||
|
||||
### Embedded interfaces
|
||||
Eine Sache, die Du bedenken solltest, ist, dass `element.(type)` nur in Kombination mit `switch` genutzt werden kann. Andernfalls musst Du auf das Komma-ok-Muster zurückgreifen.
|
||||
|
||||
The most beautiful thing is that Go has a lot of built-in logic syntax, such as anonymous fields in struct. Not suprisingly, we can use interfaces as anonymous fields as well, but we call them `Embedded interfaces`. Here, we follow the same rules as anonymous fields. More specifically, if an interface has another interface embedded within it, it will have as if it has all the methods that the embedded interface has.
|
||||
### Eingebettete Interfaces
|
||||
|
||||
We can see that the source file in `container/heap` has the following definition:
|
||||
Eine der schönsten Eigenschaften von Go ist dessen eingebaute und vorrausschauende Syntax, etwa namenlose Eigentschaften in Structs. Nicht überraschend können wir dies ebenfalls mit Interfaces tun, die `eingebettete Interfaces` genannt werden. Auch hier gelten die selben Regeln wie bei namenlosen Eigenschaften. Anders ausgedrückt: wenn ein Interface ein anderes Interface einbettet, werden auch alle Methoden mit übernommen.
|
||||
|
||||
Im Quellcode des Pakets `container/heap` lässt sich folgende Definition finden:
|
||||
|
||||
type Interface interface {
|
||||
sort.Interface // embedded sort.Interface
|
||||
Push(x interface{}) //a Push method to push elements into the heap
|
||||
Pop() interface{} //a Pop elements that pops elements from the heap
|
||||
sort.Interface // Eingetettetes sort.Interface
|
||||
Push(x interface{}) // Eine Push Methode, um Objekte im Heap zu speichern
|
||||
Pop() interface{} // Eine Pop Methode, um Elemente aus dem heap zu löschen
|
||||
}
|
||||
|
||||
We see that `sort.Interface` is an embedded interface, so the above Interface has the three methods contained within the `sort.Interface` implicitly.
|
||||
Wie wir sehen können, handelt es sich bei `sort.Interface` um ein eingebettes Interface. Es beinhaltet neben `Push()` und `Pop()` die folgenden drei Methoden implizit.
|
||||
|
||||
type Interface interface {
|
||||
// Len is the number of elements in the collection.
|
||||
// Len gibt die Anzahl der Objekte in der Datenstruktur an.
|
||||
Len() int
|
||||
// Less returns whether the element with index i should sort
|
||||
// before the element with index j.
|
||||
// Less gibt in Form eines Boolean an, ob i mit j getauscht werden sollte
|
||||
Less(i, j int) bool
|
||||
// Swap swaps the elements with indexes i and j.
|
||||
// Swap vertauscht die Elemente i und j.
|
||||
Swap(i, j int)
|
||||
}
|
||||
|
||||
Another example is the `io.ReadWriter` in package `io`.
|
||||
Ein weiteres Beispiel ist `io.ReadWriter` aus dem Paket `io`.
|
||||
|
||||
// io.ReadWriter
|
||||
type ReadWriter interface {
|
||||
@@ -356,40 +356,42 @@ Another example is the `io.ReadWriter` in package `io`.
|
||||
Writer
|
||||
}
|
||||
|
||||
### Reflection
|
||||
### Reflexion
|
||||
|
||||
Reflection in Go is used for determining information at runtime. We use the `reflect` package, and this official [article](http://golang.org/doc/articles/laws_of_reflection.html) explains how reflect works in Go.
|
||||
Reflexion in Go wird genutzt, um Informationen während der Laufzeit zu bestimmen. Wir nutzen dafür das `reflect` Paket. Der offizelle [Artikel](http://golang.org/doc/articles/laws_of_reflection.html) erklärt die Funktionsweise von `reflect` in Go.
|
||||
|
||||
There are three steps involved when using reflect. First, we need to convert an interface to reflect types (reflect.Type or reflect.Value, this depends on the situation).
|
||||
Die Nutzung von `reflect` umfasst drei Schritte. Als Erstes müssen wir ein Interface in `reflect`-Datentypen umwandeln (entweder in reflect.Type oder reflect.Value, aber dies ist Situationsabhängig).
|
||||
|
||||
t := reflect.TypeOf(i) // get meta-data in type i, and use t to get all elements
|
||||
v := reflect.ValueOf(i) // get actual value in type i, and use v to change its value
|
||||
t := reflect.TypeOf(i) // Speichert den Datentyp von i in t und erlaubt den Zugriff auf alle Elemente
|
||||
v := reflect.ValueOf(i) // Erhalte den aktuellen Wert von i. Nutze v um den Wert zu ändern
|
||||
|
||||
After that, we can convert the reflected types to get the values that we need.
|
||||
|
||||
Danach können wir die reflektierten Datentypen konvertieren, um ihre Werte zu erhalten.
|
||||
|
||||
var x float64 = 3.4
|
||||
v := reflect.ValueOf(x)
|
||||
fmt.Println("type:", v.Type())
|
||||
fmt.Println("kind is float64:", v.Kind() == reflect.Float64)
|
||||
fmt.Println("value:", v.Float())
|
||||
fmt.Println("Datentyp:", v.Type())
|
||||
fmt.Println("Die Variante ist float64:", v.Kind() == reflect.Float64)
|
||||
fmt.Println("Wert:", v.Float())
|
||||
|
||||
Finally, if we want to change the values of the reflected types, we need to make it modifiable. As discussed earlier, there is a difference between pass by value and pass by reference. The following code will not compile.
|
||||
|
||||
Wollen wir schließlich den Wert eines reflektierten Datentypen ändern, müssen wir ihn dynamisch machen. Wie vorhin angesprochen, gibt es einen Unterschied, wenn wir einen Wert als Kopie oder dessen Zeiger übergeben. Das untere Beispiel ist nicht kompilierbar.
|
||||
|
||||
var x float64 = 3.4
|
||||
v := reflect.ValueOf(x)
|
||||
v.SetFloat(7.1)
|
||||
|
||||
Instead, we must use the following code to change the values from reflect types.
|
||||
Stattdessen müssen wir den folgenden Code verwenden, um die Werte der reflektierten Datentypen zu ändern.
|
||||
|
||||
var x float64 = 3.4
|
||||
p := reflect.ValueOf(&x)
|
||||
v := p.Elem()
|
||||
v.SetFloat(7.1)
|
||||
|
||||
We have just discussed the basics of reflection, however you must practice more in order to understand more.
|
||||
|
||||
Nun kennen wir die Grundlagen der Reflexion. Es erfordert jedoch noch ein wenig Übung, um sich mit diesem Konzept vertraut zu machen.
|
||||
|
||||
## Links
|
||||
|
||||
- [Directory](preface.md)
|
||||
- Previous section: [Object-oriented](02.5.md)
|
||||
- Next section: [Concurrency](02.7.md)
|
||||
- [Inhaltsverzeichnis](preface.md)
|
||||
- Vorheriger Abschnitt: [Objektorientierte Programmierung](02.5.md)
|
||||
- Nächster Abschnitt: [Nebenläufigkeit](02.7.md)
|
||||
Reference in New Issue
Block a user