Определение и вызов функций в Go
Cloud Server | Комментировать запись
Функция – это фрагмент кода, который после определения можно использовать повторно. Функции нужны для того, чтобы упростить код и сделать его долее читабельным, разбив его на небольшие понятные задачи, которые можно использовать много раз внутри программы.
Go предоставляет мощную стандартную библиотеку, которая имеет много предопределенных функций. С пакетом fmt вы, вероятно, уже знакомы:
- fmt.Println() выводит объекты на стандартный вывод (скорее всего, это ваш терминал).
- fmt.Printf() позволяет форматировать полученный вывод.
Имена функций всегда включают круглые скобки и могут содержать параметры.
В этом мануале вы узнаете, как определить собственные функции для своих программ.
Определение функции
Давайте попробуем для начала превратить классическую программу «Hello, World!» в функцию.
Для этого мы создадим новый текстовый файл и вызовем программу hello.go. Затем мы определим функцию.
Функция определяется с помощью ключевого слова func. Затем следует имя (можно выбрать любое) и скобки, где содержатся все параметры, которые примет функция (если параметров нет, скобки будут пустыми). Строки кода функции заключаются в фигурные скобки {}.
Давайте определим функцию по имени hello():
func hello() {}
Это начальный оператор для создания функции.
Сюда мы добавим вторую строку, чтобы предоставить инструкции о том, что делает эта функция. В данном случае функция должна выводить фразу «Hello, World!» на консоль:
func hello() {
fmt.Println("Hello, World!")
}
Теперь функция полностью определена, но если мы запустим программу на этом этапе, ничего не произойдет, так как мы не вызвали функцию.
Следовательно, нужно вызвать функцию hello() внутри блока функции main():
package main
import "fmt"
func main() {
hello()
}
func hello() {
fmt.Println("Hello, World!")
}
Теперь давайте запустим программу:
go run hello.go
Вы получите следующий вывод:
Hello, World!
Обратите внимание, что мы также ввели в код функцию main() – это специальная функция, которая сообщает компилятору, что именно здесь должна начинаться программа. Любая исполняемая программа (которую можно запустить из командной строки) должна содержать функцию main(). Функция main() должна появляться в коде только один раз, находиться в пакете main(), и не получать и не возвращать никаких аргументов. Это позволяет выполнять программы в Go. Посмотрите на следующий пример:
package main
import "fmt"
func main() {
fmt.Println("this is the main section of the program")
}
Функции могут быть намного сложнее, чем определенная нами функция hello(). В функциях мы можем использовать циклы for, условные операторы и многое другое.
Читайте также: Условные операторы в Go
Например, следующая функция использует условный оператор, чтобы проверить, есть ли гласный во входных данных для переменной name, а затем использует цикл for для перебора букв в строке name.
package main
import (
"fmt"
"strings"
)
func main() {
names()
}
func names() {
fmt.Println("Enter your name:")
var name string
fmt.Scanln(&name)
// Check whether name has a vowel
for _, v := range strings.ToLower(name) {
if v == 'a' || v == 'e' || v == 'i' || v == 'o' || v == 'u' {
fmt.Println("Your name contains a vowel.")
return
}
}
fmt.Println("Your name does not contain a vowel.")
}
Функция names (), которую мы здесь определяем, устанавливает переменную name с помощью input, а затем устанавливает условный оператор в цикле for. Это показывает, как код может быть организован в определении функции. Однако, в зависимости от того, что мы намерены использовать в нашей программе и как мы хотим настроить наш код, мы можем захотеть определить условный оператор и цикл for как две отдельные функции.
Определение функций в программе делает наш код модульным и многократно используемым, так что мы можем вызывать одни и те же функции, не переписывая их.
Работа с параметрами
До сих пор мы рассматривали функции с пустыми скобками, которые не принимают аргументов, но в скобках можно определять параметры для функций.
Параметр – это именованная сущность в определении функции, указывающая аргумент, который может принимать данная функция. В Go нужно указывать тип данных для каждого параметра.
Читайте также: Основные типы данных в Go
Давайте создадим программу, которая повторяет слово определенное количество раз. Потребуется строковый параметр с именем word и параметр int с именем reps для количества повторений слова.
package main
import "fmt"
func main() {
repeat("8host", 5)
}
func repeat(word string, reps int) {
for i := 0; i < reps; i++ {
fmt.Print(word)
}
}
Мы передали значение 8host для параметра word и 5 для параметра reps. Значения соответствуют параметрам в том порядке, в котором они были заданы. Функция repeat имеет цикл for, который будет повторяться столько раз, сколько указано параметром reps. Для каждой итерации выводится значение параметра word.
Вот вывод этой программы:
8host8host8host8host8host
Если у вас есть набор параметров с одинаковыми значениями, вы можете не указывать тип каждый раз. Давайте создадим небольшую программу, которая принимает параметры x, y и z, и пусть все они принимают значения типа int. Мы создадим функцию, которая складывает значения параметров в разных конфигурациях. Их суммы будут выведены функцией на экран. Затем мы вызовем функцию и передадим ей числа.
package main
import "fmt"
func main() {
addNumbers(1, 2, 3)
}
func addNumbers(x, y, z int) {
a := x + y
b := x + z
c := y + z
fmt.Println(a, b, c)
}
Когда мы создавали сигнатуру функции для addNumbers, нужно было указать тип только в конце, а не каждый раз.
Мы передали число 1 для параметра x, 2 для y и 3 для z. Эти значения соответствуют каждому параметру в указанном порядке.
Программа выполняет следующие вычисления на основе значений, которые мы передали параметрам:
a = 1 + 2
b = 1 + 3
c = 2 + 3
Функция также выводит a, b и c, и, исходя из заданных значений, мы ожидаем, что a будет равно 3, b 4, а c – 5. Давайте запустим программу:
go run add_numbers.go
3 4 5
Когда мы передаем 1, 2 и 3 в качестве параметров функции addNumbers(), мы получаем ожидаемый результат.
Параметры – это аргументы, которые обычно задаются в определениях функций как переменные. Передавая аргументы функции, вы можете присвоить им значения при запуске метода.
Возврат значения
Функции можно передать значение параметра, но и функция также может создать значение.
Функция может сделать это с помощью оператора return, который выйдет из функции и при необходимости передаст выражение вызывающей стороне. Тип возвращаемых данных нужно указывать.
Ранее в функциях вместо оператора return мы использовали оператор fmt.Println(). Давайте создадим программу, которая будет возвращать переменную.
В новом текстовом файле double.go мы напишем программу, которая удваивает значение параметра x и возвращает переменную y. Мы вызываем вывод переменной result, который получается в результате запуска функции double(3):
package main
import "fmt"
func main() {
result := double(3)
fmt.Println(result)
}
func double(x int) int {
y := x * 2
return y
}
Давайте запустим программу:
go run double.go
6
В качестве выходных данных возвращается целое число 6 – это правильный результат умножения 3 на 2.
Если функция указывает возврат, вы должны предоставить его как часть кода. Если вы этого не сделаете, вы получите ошибку компиляции.
Чтобы продемонстрировать это, давайте закомментируем строку с оператором return:
package main
import "fmt"
func main() {
result := double(3)
fmt.Println(result)
}
func double(x int) int {
y := x * 2
// return y
}
А теперь давайте снова запустим программу:
go run double.go
./double.go:13:1: missing return at end of function
Без оператора return программа не может быть скомпилирована.
Функции завершаются сразу же после обработки оператором return, даже если этот оператор находится не в конце функции:
package main
import "fmt"
func main() {
loopFive()
}
func loopFive() {
for i := 0; i < 25; i++ {
fmt.Print(i)
if i == 5 {
// Stop function at i == 5
return
}
}
fmt.Println("This line will not execute.")
}
Здесь написан цикл for на 25 итераций. Однако внутри цикла for есть условный оператор if, который проверяет, равно ли значение i 5. Если это так, он выдает оператор return. Поскольку мы находимся в функции loopFive, return в любой точке функции приведет к завершению функции. В результате программа никогда не доберется до последней строки в этой функции, чтобы отобразить строку «This line will not execute».
Использование оператора return в цикле for завершает функцию, поэтому строка, находящаяся вне цикла, не будет выполняться. Если бы вместо него мы использовали оператор break, то в этом месте закончился бы только цикл, и последняя строка fmt.Println() запустилась бы.
Читайте также: Операторы break и continue в циклах Go
Оператор return прерывает функцию и может возвращать значение, если оно указано в сигнатуре функции.
Возврат нескольких значений
Функции можно задать более одного возвращаемого значения. Давайте рассмотрим программу repeat.go и сделаем так, чтобы она возвращала два значения: первое значение будет повторяемым, а второе будет ошибкой, которая возникнет, если параметр reps меньше 0:
package main
import "fmt"
func main() {
val, err := repeat("8host", -1)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(val)
}
func repeat(word string, reps int) (string, error) {
if reps <= 0 {
return "", fmt.Errorf("invalid value of %d provided for reps. value must be greater than 0.", reps)
}
var value string
for i := 0; i < reps; i++ {
value = value + word
}
return value, nil
}
Сначала функция repeat проверяет, является ли значение аргумента reps допустимым. Любое значение меньше 0 приведет к ошибке. Поскольку мы передали значение -1, эта ветвь кода будет выполнена. Обратите внимание, что, выходя из функции, мы должны предоставить string и error. Поскольку предоставленные аргументы привели к ошибке, для первого значения return будет пустая строка, а для второго значения return будет ошибка.
Мы можем получить оба значения в функции main(), объявив две новые переменные, value и err. Поскольку в возврате может быть ошибка, нужно проверить, не получили ли мы ошибку, прежде чем продолжить работу программы. В этом примере мы получили ошибку. Мы выводим ее и выходим из функции main(), что завершит работу программы.
Если бы ошибки не было, программа бы вывела значение функции.
Примечание: Рекомендуется возвращать только два или три значения. Кроме того, все ошибки всегда должны возвращаться как последнее значение функции.
Программа выведет такой результат:
invalid value of -1 provided for reps. value must be greater than 0.
В этом разделе мы рассмотрели, как оператор return может возвращать несколько значений из функции.
Заключение
Функции – это блоки кода, которые выполняют действия внутри программы, что позволяет сделать код многоразовым и модульным.
Читайте также: Как писать Go-пакеты
Tags: Go, Google