Треки
/
Go
Go
/
Салабус
/
Функції
Фу

Функції у Go

1 вправа

Про концепцію Функції

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

Параметри функції

Усі параметри повинні мати явно вказаний тип; для параметрів немає виведення типу. Типових значень для параметрів немає, тому всі параметри функції обовʼязкові.

import "fmt"

// No parameters
func PrintHello() {
    fmt.Println("Hello")
}

// One parameter
func PrintHelloName(name string) {
  fmt.Println("Hello " + name)
}

Параметри одного типу можна оголошувати разом, указавши один спільний тип після них.

import "fmt"

func PrintGreetingName(greeting, name string) {
  fmt.Println(greeting + " " + name)
}

Параметри проти аргументів

Швидко розгляньмо два терміни, які часто плутають: parameters і arguments. Параметри функції - це назви, визначені в сигнатурі функції, як-от greeting і name у функції PrintGreetingName вище. Аргументи функції - це конкретні значення, які передаються параметрам функції, коли ми викликаємо функцію. Наприклад, у прикладі нижче "Hello" і "Katrina" - це аргументи, передані параметрам greeting і name:

PrintGreetingName("Hello", "Katrina")

Повернені значення

Після параметрів функції йде нуль або більше повернених значень, які теж потрібно явно типізувати. Одиничне повернене значення записують без дужок, а кілька повернених значень беруть у дужки. Значення повертаються у викликаний код із функцій за допомогою ключового слова return. У функції може бути кілька інструкцій return. Виконання функції завершується тієї ж миті, коли воно доходить до однієї з таких інструкцій return. Якщо з функції потрібно повернути кілька значень, їх розділяють комами. Більше про ідіоматичне використання кількох повернених значень можна дізнатися в повʼязаній концепції.

func Hello(name string) string {
  return "Hello " + name
}

func HelloAndGoodbye(name string) (string, string) {
  return "Hello " + name, "Goodbye " + name
}

Виклик функцій

Щоб викликати функцію, треба вказати її назву та передати аргументи для кожного параметра функції в дужках.

import "fmt"

// No parameters, no return value
func PrintHello() {
    fmt.Println("Hello")
}
// Called like this:
PrintHello()

// One parameter, one return value
func Hello(name string) string {
  return "Hello " + name
}
// Called like this:
greeting := Hello("Dave")

// Multiple parameters, multiple return values
func SumAndMultiply(a, b int) (int, int) {
    return a+b, a*b
}
// Called like this:
aplusb, atimesb := SumAndMultiply(a, b)

Іменовані повернені значення та «голий» return

Як і параметри, повернені значення можна за бажанням іменувати. Якщо використано іменовані повернені значення, то інструкція return без аргументів поверне саме їх. Це називають «голим» поверненням.

func SumAndMultiplyThenMinus(a, b, c int) (sum, mult int) {
    sum, mult = a+b, a*b
    sum -= c
    mult -= c
    return
}

Передача за значенням проти передачі за посиланням

Також важливо зʼясувати, що означає передача за значенням і передача за посиланням.

Спершу зʼясуймо передачу за значенням. У прикладі нижче, коли ми передаємо змінну val у функцію MultiplyByTwo, ми передаємо копію val. Через це newVal має оновлене значення 4, але початкова змінна val усе ще дорівнює 2. По суті, Go створює копію початкового значення, тож функція змінює лише цю копію, тобто v.

val := 2
func MultiplyByTwo(v int) int {
    v = v * 2
    return v
}
newVal := MultiplyByTwo(val)
// newval is 4, val is still 2 because only a copy of its value was passed into the function

Строго кажучи, у Go всі аргументи передаються за значенням, тобто створюється копія значення чи даних, наданих функції. Але якщо ми не хочемо створювати копію даних, переданих у функцію, і хочемо змінити ці дані всередині функції, то варто використати pointers як аргументи, тобто передати за посиланням.

Вказівники

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

Поки що достатньо знати, що типи-вказівники можна розпізнати за * перед типом у сигнатурі функції.

func HandlePointers(x, y *int) {
    // Some logic to handle integer values referenced by pointers x and y
}

Якщо поняття pointer здається заплутаним, не варто хвилюватися. Далі в силабусі є окремий розділ, який допоможе нам опанувати вказівники.

Винятки

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

Інші різновиди функцій

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

Редагувати через GitHub Посилання відкривається в новому вікні або вкладці

Вивчити концепцію Функції