Tracks
/
Go
Go
/
Übungen
/
Kartentricks
Kartentricks

Kartentricks

Lernübung

Einführung

Slices

Slices in Go ähneln Listen oder Arrays in anderen Sprachen. Sie enthalten mehrere Elemente eines bestimmten Typs (oder Interfaces).

Slices in Go basieren auf Arrays. Arrays haben eine feste Größe. Ein Slice ist dagegen eine dynamisch große, flexible Sicht auf die Elemente eines Arrays.

Ein Slice wird als []T geschrieben, wobei T der Typ der Elemente im Slice ist:

var empty []int                 // an empty slice
withData := []int{0,1,2,3,4,5}  // a slice pre-filled with some data

Du kannst ein Element an einem bestimmten, nullbasierten Index mit der eckigen Klammernotation abrufen oder setzen:

withData[1] = 5
x := withData[1] // x is now 5

Du kannst aus einem vorhandenen Slice einen neuen Slice erzeugen, indem du einen Bereich von Elementen abrufst. Auch hier verwendest du die eckige Klammernotation, gibst aber sowohl einen Startindex (inklusive) als auch einen Endindex (exklusiv) an. Wenn du keinen Startindex angibst, ist er standardmäßig 0. Wenn du keinen Endindex angibst, ist er standardmäßig die Länge des Slices.

newSlice := withData[2:4]
// => []int{2,3}
newSlice := withData[:2]
// => []int{0,1}
newSlice := withData[2:]
// => []int{2,3,4,5}
newSlice := withData[:]
// => []int{0,1,2,3,4,5}

Mit der Funktion append kannst du Elemente zu einem Slice hinzufügen. Im Folgenden hängen wir 4 und 2 an den Slice a an.

a := []int{1, 3}
a = append(a, 4, 2)
// => []int{1,3,4,2}

append gibt immer einen neuen Slice zurück. Wenn wir nur Elemente an einen vorhandenen Slice anhängen wollen, ist es üblich, das Ergebnis wieder der Slice-Variablen zuzuweisen, die wir als erstes Argument übergeben, so wie oben.

Mit append kannst du auch zwei Slices zusammenführen:

nextSlice := []int{100,101,102}
newSlice  := append(withData, nextSlice...)
// => []int{0,1,2,3,4,5,100,101,102}

Variadische Funktionen

Normalerweise akzeptieren Funktionen in Go nur eine feste Anzahl von Argumenten. Es ist aber auch möglich, in Go variadische Funktionen zu schreiben.

Eine variadische Funktion ist eine Funktion, die eine variable Anzahl von Argumenten akzeptiert.

Wenn dem Typ des letzten Parameters in einer Funktionsdefinition eine Ellipse ... vorangestellt ist, kann die Funktion beliebig viele Argumente für diesen Parameter akzeptieren.

func find(a int, b ...int) {
    // ...
}

In der obigen Funktion ist der Parameter b variadisch, und wir können 0 oder mehr Argumente an b übergeben.

find(5, 6)
find(5, 6, 7)
find(5)
Caution

Der variadische Parameter muss der letzte Parameter der Funktion sein.

Variadische Funktionen funktionieren, indem die variable Anzahl von Argumenten in einen Slice des Typs des variadischen Parameters umgewandelt wird.

Hier ist ein Beispiel für die Implementierung einer variadischen Funktion.

func find(num int, nums ...int) {
    fmt.Printf("type of nums is %T\n", nums)

    for i, v := range nums {
        if v == num {
            fmt.Println(num, "found at index", i, "in", nums)
            return
        }
    }

    fmt.Println(num, "not found in ", nums)
}

func main() {
    find(89, 90, 91, 95)
    // =>
    // type of nums is []int
    // 89 not found in  [90 91 95]

    find(45, 56, 67, 45, 90, 109)
    // =>
    // type of nums is []int
    // 45 found at index 2 in [56 67 45 90 109]

    find(87)
    // =>
    // type of nums is []int
    // 87 not found in  []
}

In der Zeile find(89, 90, 91, 95) des obigen Programms sind die variablen Argumente der Funktion find die Werte 90, 91 und 95. Die Funktion find erwartet nach num einen variadischen Parameter vom Typ int. Daher wandelt der Compiler diese drei Argumente in einen Slice vom Typ int um, []int{90, 91, 95}, und übergibt ihn dann als nums an die Funktion find.

Manchmal hast du bereits einen Slice und möchtest ihn an eine variadische Funktion übergeben. Das erreichst du, indem du den Slice gefolgt von ... übergibst. Das weist den Compiler an, den Slice unverändert in der variadischen Funktion zu verwenden. Der oben beschriebene Schritt, bei dem ein Slice erzeugt wird, entfällt in diesem Fall einfach.

list := []int{1, 2, 3}
find(1, list...) // "find" defined as shown above

Anleitung

Als angehende Zauberin muss Elyse ein paar Grundlagen üben. Sie hat einen Stapel Karten, den sie manipulieren möchte.

Um es etwas einfacher zu machen, benutzt sie nur die Karten 1 bis 10.

1. Einen Slice mit bestimmten Karten erstellen

Beim Üben mit ihren Karten beginnt Elyse am liebsten mit ihren drei Lieblingskarten des Decks: 2, 6 und 9. Schreibe eine Funktion FavoriteCards, die einen Slice mit diesen Karten in dieser Reihenfolge zurückgibt.

cards := FavoriteCards()
fmt.Println(cards)
// Output: [2 6 9]

2. Eine Karte aus einem Stapel abrufen

Gib die Karte an der Position index aus dem gegebenen Stapel zurück.

card := GetItem([]int{1, 2, 4, 1}, 2) // card == 4

Wenn der Index außerhalb des gültigen Bereichs liegt (also negativ ist oder hinter dem Ende des Stapels), möchten wir -1 zurückgeben:

card := GetItem([]int{1, 2, 4, 1}, 10) // card == -1
Note

Nach Konvention in Go gibt man einen Fehler zurück, statt einen „out-of-bounds"-Wert zurückzugeben. Hier ist der „out-of-bounds"-Wert -1, wenn eine positive Ganzzahl erwartet wird. Wenn man einen Fehler zurückgibt, gilt es als idiomatisch, den zero value zusammen mit dem Fehler zurückzugeben. Einen Fehler mit dem passenden Rückgabewert zurückzugeben, wird in einer späteren Übung behandelt.

3. Eine Karte im Stapel austauschen

Tausche die Karte an der Position index gegen die angegebene neue Karte aus und gib den angepassten Stapel zurück. Beachte, dass dies den Eingabe-Slice verändert, was das erwartete Verhalten ist.

index := 2
newCard := 6
cards := SetItem([]int{1, 2, 4, 1}, index, newCard)
fmt.Println(cards)
// Output: [1 2 6 1]

Wenn der Index außerhalb des gültigen Bereichs liegt (also negativ ist oder hinter dem Ende des Stapels), möchten wir die neue Karte am Ende des Stapels anhängen:

index := -1
newCard := 6
cards := SetItem([]int{1, 2, 4, 1}, index, newCard)
fmt.Println(cards)
// Output: [1 2 4 1 6]

4. Karten oben auf den Stapel legen

Füge die im Parameter value angegebenen Karten oben auf den Stapel hinzu.

slice := []int{3, 2, 6, 4, 8}
cards := PrependItems(slice, 5, 1)
fmt.Println(cards)
// Output: [5 1 3 2 6 4 8]

Wenn kein Argument für den Parameter value angegeben wird, dann entspricht das Ergebnis dem ursprünglichen Slice.

slice := []int{3, 2, 6, 4, 8}
cards := PrependItems(slice)
fmt.Println(cards)
// Output: [3 2 6 4 8]

5. Eine Karte aus dem Stapel entfernen

Entferne die Karte an der Position index aus dem Stapel und gib den Stapel zurück. Beachte, dass dies den Eingabe-Slice verändern kann, was in Ordnung ist.

cards := RemoveItem([]int{3, 2, 6, 4, 8}, 2)
fmt.Println(cards)
// Output: [3 2 4 8]

Wenn der Index außerhalb des gültigen Bereichs liegt (also negativ ist oder hinter dem Ende des Stapels), möchten wir den Stapel unverändert lassen:

cards := RemoveItem([]int{3, 2, 6, 4, 8}, 11)
fmt.Println(cards)
// Output: [3 2 6 4 8]
Über GitHub bearbeiten Der Link öffnet sich in einem neuen Fenster oder Tab
Go Exercism

Bereit, mit Kartentricks zu starten?

Melde dich bei Exercism an, um Go mit 34 Konzepte165 Übungen und echtem menschlichen Mentoring zu lernen und zu meistern, alles kostenlos.