cpp

Способы возврата значения из функции

Вернуть значение из функции позволяет оператор return. После исполнения этого оператора выполнение функции останавливается и управление передается обратно в точку вызова функции. Это означает, что инструкции после оператора return никогда не будут выполнены. Если внутри функции нет оператора return, то по достижении закрывающей фигурной скобки управление будет передано в точку вызова функции.

При использовании оператора return не должно быть неоднозначных ситуаций. Например, в этом случае возвращаемое значение зависит от условия:

func sum(x int, y int) int { // Ошибка!
   if x > 0 {
      return x + y
   }
}

При компиляции будет выведено сообщение об ошибке: missing return at end of function. Чтобы избежать подобной ситуации, следует в конце тела функции вставить оператор return со значением по умолчанию:

func sum(x int, y int) int {
   if x > 0 {
      return x + y
   }
   return 0
}

Если функция ничего не возвращает, то оператора return может не быть. Однако, если необходимо досрочно прервать выполнение функции, то оператор return указывается без возвращаемого значения. Пример:

func printOK() {
   fmt.Println("OK")
   return // Преждевременное завершение функции
   fmt.Println("Эта инструкция никогда не будет выполнена!!!")
}

Вызов функции, не возвращающей никакого значения, нельзя размещать внутри какого-либо выражения. Только в отдельной инструкции.

Возврат одного значения

Параметр <Тип результата> в определении функции задает тип возвращаемого значения. Значение этого типа должно быть указано в операторе return. В этом случае возвращается копия значения. Если функция не возвращает никакого значения, то тип возвращаемого значения не указывается.

Пример функции не возвращающей никакого значения:

func Print(msg string) {
   fmt.Println(msg)
}

Пример функции, возвращающей копию значения типа int:

func Sum(x int, y int) int {
   return x + y
}

Вызов функции, возвращающей какое-либо значение, можно разместить внутри выражения с правой стороны от оператора =. Возвращаемое значение можно присвоить переменной или просто проигнорировать, например, как мы это сделали при вызове функции Println(). Пример сохранения значения, возвращаемого функцией, в переменной:

z := Sum(10, 20)

Функция может вернуть значение любого типа. Давайте создадим несколько функций, возвращающих различные типы данных (листинг 10.2).

Листинг 10.2. Возврат одного значения из функции

package main

import (
   "fmt"
   "math"
   "time"
)

func main() {
   // Вызов функций
   fmt.Println(Sum(10, 20))          // 30
   fmt.Println(Pi())                 // 3.141592653589793
   fmt.Println(GetFirstChar("тест")) // 1090
   fmt.Println(GetDate())            // 24.03.2022
   fmt.Println(CreateArray())        // [1 2 3]
   fmt.Println(CreateSlice())        // [1 2 3]
   fmt.Println(GetTime())
   // 2022-03-24 19:54:41.056545 +0300 MSK m=+0.020013301
   p := GetPointer()
   fmt.Println(*p)                   // 10
}
func Sum(x int, y int) int {         // Возврат целого числа
   return x + y
}
func Pi() float64 {                  // Возврат вещественного числа
   return math.Pi
}
func GetFirstChar(s string) rune {   // Возврат символа
   arr := []rune(s)
   if len(arr) == 0 {
      return '\x00'
   }
   return arr[0]
}
func GetDate() string {              // Возврат строки
   return time.Now().Format("02.01.2006")
}
func CreateArray() [3]int {          // Возврат массива
   return [3]int{1, 2, 3}
}
func CreateSlice() []int {           // Возврат слайса
   return []int{1, 2, 3}
}
func GetTime() time.Time {           // Возврат структуры
   return time.Now()
}
func GetPointer() *int {             // Возврат указателя
   n := 10
   p := new(int)
   *p = n
   return p
}

Особое внимание следует обратить внимание на возврат указателя из функции. Внутри функции GetPointer() мы объявляем локальную переменную n, затем выделяем динамическую память явным образом и сохраняем в ней значение переменной n. Указатель на динамическую память мы возвращаем из функции. На самом деле в языке Go мы можем написать так:

func GetPointer() *int {             // Возврат указателя
   n := 10
   return &n
}

Ой-ой-ой. Скажут опытные программисты, знакомые с другими языками программирования. Что же ты делаешь? Ты же возвращаешь указатель на локальную переменную, которая будет уничтожена при выходе из функции. Спокойствие. Только спокойствие. Действительно, в языке C++ подобный код приведет к неопределенному поведению программы, но не в Go! Сборщик мусора языка Go следит за подобными ситуациями. Если из функции возвращается указатель на локальные переменные, то сборщик мусора не будет удалять переменную, пока на нее существует хотя бы одна ссылка. Так что никаких проблем в этом случае не будет.

Возврат нескольких значений

Из функции можно вернуть сразу несколько значений. В этом случае в параметре <Тип результата> типы возвращаемых значений перечисляются через запятую внутри круглых скобок. В операторе return возвращаемые значения указываются через запятую. Пример возврата двух значений из функции приведен в листинге 10.3.

Листинг 10.3. Возврат нескольких значений из функции

package main

import "fmt"

func main() {
   arr := []int{2, 5, 6, 1, 3}
   // Получение всех значений
   min, max := MinMax(arr)
   fmt.Println("min =", min)
   fmt.Println("max =", max)
   // Получение только первого значения
   min, _ = MinMax(arr)
   fmt.Println("min =", min)
   // Получение только второго значения
   _, max = MinMax(arr)
   fmt.Println("max =", max)
}
func MinMax(arr []int) (int, int) {
   min := arr[0]
   max := arr[0]
   for _, value := range arr {
      if value < min {
         min = value
      }
      if value > max {
         max = value
      }
   }
   return min, max
}

Именованные возвращаемые значения

Возвращаемым значениям можно дать имена, которые становятся локальными переменными. В этом случае в параметре <Тип результата> названия и типы возвращаемых значений перечисляются через запятую внутри круглых скобок. В операторе return возвращаемые значения перечисляются через запятую или значения вообще не указываются. Пример возврата именованных значений из функции приведен в листинге 10.4.

Листинг 10.4. Именованные возвращаемые значения

package main

import "fmt"

func main() {
   arr := []int{2, 5, 6, 1, 3}
   min, max := MinMax(arr)
   fmt.Println("min =", min)
   fmt.Println("max =", max)
   fmt.Println(test())
}
func test() (a int) {
   a = 20
   return
}
func MinMax(arr []int) (min int, max int) {
   min = arr[0]
   max = arr[0]
   for _, value := range arr {
      if value < min {
         min = value
      }
      if value > max {
         max = value
      }
   }
   // return min, max
   return
}

Учебник Go (Golang)
Учебник Go (Golang) в формате PDF

Помощь сайту

ЮMoney (Yandex-деньги): 410011140483022

ПАО Сбербанк:
Счет: 40817810855006152256
Реквизиты банка:
Наименование: СЕВЕРО-ЗАПАДНЫЙ БАНК ПАО СБЕРБАНК
Корреспондентский счет: 30101810500000000653
БИК: 044030653
КПП: 784243001
ОКПО: 09171401
ОКОНХ: 96130
Скриншот реквизитов

cpp