Треки
/
Go
Go
/
Вправи
/
Карткові фокуси
Карткові фокуси

Карткові фокуси

Навчальна вправа

Вступ

Зрізи

Зрізи в Go схожі на масиви в інших мовах. Вони містять кілька елементів певного типу (або інтерфейсу).

Зрізи в Go базуються на масивах. Масиви мають фіксований розмір. Зріз же - це динамічно розмірне, гнучке подання елементів масиву.

Зріз записують як []T, де T - це тип елементів у зрізі:

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

Можна отримати або встановити елемент за заданим індексом, що відраховується від нуля, використовуючи запис у квадратних дужках:

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

Можна створити новий зріз з наявного зрізу, взявши діапазон елементів. Знову ж таки, використовуючи квадратні дужки, але вказуючи як початковий (включно), так і кінцевий (не включно) індекс. Якщо не вказати початковий індекс, він типово дорівнює 0. Якщо не вказати кінцевий індекс, він типово дорівнює довжині зрізу.

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}

Можна додавати елементи до зрізу за допомогою функції append. Нижче ми додаємо 4 і 2 до зрізу a.

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

append завжди повертає новий зріз, і коли ми просто хочемо додати елементи до наявного зрізу, зазвичай результат знову присвоюють тій самій змінній зрізу, яку ми передали першим аргументом, як це зроблено вище.

append також можна використати, щоб обʼєднати два зрізи:

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

Варіативні функції

Зазвичай функції в Go приймають лише фіксовану кількість аргументів. Однак у Go можна також писати варіативні функції.

Варіативна функція - це функція, яка приймає змінну кількість аргументів.

Якщо перед типом останнього параметра у визначенні функції стоїть трикрапка ..., тоді функція може приймати будь-яку кількість аргументів для цього параметра.

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

У наведеній вище функції параметр b варіативний, і ми можемо передати b 0 або більше аргументів.

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

Варіативний параметр має бути останнім параметром функції.

Варіативні функції працюють так: змінну кількість аргументів перетворюють на зріз типу варіативного параметра.

Ось приклад реалізації варіативної функції.

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  []
}

У рядку find(89, 90, 91, 95) наведеної вище програми змінною кількістю аргументів функції find є 90, 91 і 95. Функція find приймає варіативний параметр типу int після num. Отже, компілятор перетворить ці три аргументи на зріз типу int []int{90, 91, 95} і потім передасть його функції find як nums.

Іноді в нас уже є зріз, і ми хочемо передати його варіативній функції. Це можна зробити, передавши зріз, а після нього .... Це вкаже компілятору використати зріз як є всередині варіативної функції. Крок, описаний вище, де створюється зріз, у цьому випадку просто пропускається.

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

Вказівки

Як майбутня фокусниця, Еліз має потренуватися в основах. У неї є стос карт, з якими вона хоче працювати.

Щоб трохи спростити собі справу, вона використовує лише карти від 1 до 10.

1. Створити зріз із певними картами

Практикуючись зі своїми картами, Еліз любить починати з трьох улюблених карт колоди: 2, 6 і 9. Напишіть функцію FavoriteCards, яка повертає зріз із цими картами в такому порядку.

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

2. Отримати карту зі стосу

Поверніть карту на позиції index із заданого стосу.

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

Якщо індекс виходить за межі (тобто якщо він відʼємний або після кінця стосу), потрібно повернути -1:

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

У Go за домовленістю замість повернення значення «поза межами» повертають помилку. Тут значенням «поза межами» є -1, коли на цьому місці має бути додатне ціле число. Повертаючи помилку, ідіоматично повертати разом із нею zero value. Повернення помилки разом із належним значенням буде розглянуто в одній із наступних вправ.

3. Замінити карту в стосі

Замініть карту на позиції index на надану нову карту й поверніть змінений стос. Зауважте, що це змінить вхідний зріз, і саме така поведінка очікується.

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

Якщо індекс виходить за межі (тобто якщо він відʼємний або після кінця стосу), потрібно додати нову карту в кінець стосу:

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

4. Додати карти на верхівку стосу

Додайте карту (або карти), указану в параметрі value, на верхівку стосу.

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

Якщо для параметра value не передано жодного аргументу, результат дорівнює початковому зрізу.

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

5. Вилучити карту зі стосу

Вилучіть карту на позиції index зі стосу й поверніть стос. Зауважте, що це може змінити вхідний зріз, і це нормально.

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

Якщо індекс виходить за межі (тобто якщо він відʼємний або після кінця стосу), потрібно залишити стос без змін:

cards := RemoveItem([]int{3, 2, 6, 4, 8}, 11)
fmt.Println(cards)
// Output: [3 2 6 4 8]
Редагувати через GitHub Посилання відкривається в новому вікні або вкладці
Go Exercism

Час розпочати Карткові фокуси?

Зареєструйтеся на Exercism, щоб вивчати й опановувати Go, а також 34 концепції165 вправ та справжнє наставництво від людей, і все це безкоштовно.