Предыдущая часть — часть 8 – циклы.
Функция — это группа операторов, которые вместе выполняют определённую задачу. В каждой программе Go имеется как имнимум одна функция, которая называется main(). Кроме неё — вы можете разбить код на другие функции по вашему усмотрению, но логически каждая функция должна выполнять определённую задачу.
Объявление (declaration) функции указывает компилятору имя функции, тип возвращаемого значения (или значений) и её аргументы. Описание (definition) функции включает в себя непоследственно тело фнукции.
Стандартная библиотека Go предоставляет большой набор встроенных функций, которые вы можете использовать в своих программах, например — функция len() принимает объект в виде аргумента и возвращет длину элементов в этом объекте:
package main
import "fmt"
func main() {
var a [5]int
fmt.Printf("len array called a: %d\n", len(a));
}
Результат:
[simterm]
$ go run len.go
len array called a: 5
[/simterm]
Содержание
Описание функции
Синтаксис описания функции:
func function_name( [parameter list] ) [return_types]
{
body of the function
}
Описание состоит из заголовка функции и тела фукнции.
Остальные части из примера синтаксиса выше:
func— объявление о начале описания функцииfunction_name— имя фукнцииparameter list— список параметров функции. При вызове функции и передаче ей параметров — в параметре указыавется значение, которое называется аргументом функции. В списке параметров указывается тип принимаемого аргумента, порядок параметров, и их количество. Параметры функции являются опциональными, т.е. функция может не иметь параметров вообще.return_types— возврщаемое значение или значения, в которых указываются типы данных, которые возвращает функция. Функция может не возвращать никаких значени й вообще, в таком случаеreturn_typesможно не указывать.body of the function— тело функции, в котором указываются операторы и выражения для выполнения операции
Пример
В следующем коде демонстрируется функция с именем max(), которая принимает два параметра — num1 и num2, и возвращает большее из них:
/* function returning the max between two numbers */
func max(num1, num2 int) int {
/* local variable declaration */
result int
if (num1 > num2) {
result = num1
} else {
result = num2
}
return result
}
Вызов функции
Когда вы создаёте функцию — вы указывает её описание, и что она будет делать. Для её использования — вам необходимо вызвать эту функцию.
Когда программа вызывает функцию — она передаёт управление выполнением программы этой функции: функция выполняет необходимую задачу, и когда она достигает оператора return или замыкающей фигурной скобки — она передаёт контроль выполнения обратно программме.
Для вызова функции вы просто указываете имя функции и необходимые параметры. Если функция возвращает какое-либо значение — вы можете сохранить его в переменную:
package main
import (
"fmt"
"os"
"strconv"
)
func main() {
// pass two args to a, b vartiables, convert them to integer
a, _ := strconv.Atoi(os.Args[1])
b, _ := strconv.Atoi(os.Args[2])
// define variable to return
var ret int
// calling a function to get max value
ret = max(a, b)
fmt.Printf( "Max value is : %d\n", ret )
}
/* function returning the max between two numbers */
func max(num1, num2 int) int {
// local variable declaration
var result int
if (num1 > num2) {
result = num1
} else {
result = num2
}
return result
}
Результат выполнения этой программы:
[simterm]
$ go run max.go 100 200
Max value is : 200
[/simterm]
Возврат нескольких значений
В Go функция может вернуть не одно, а два и более значений, например:
package main
import (
"fmt"
"os"
)
func swap(x, y string) (string, string) {
return y, x
}
func main() {
var a string = os.Args[1]
var b string = os.Args[2]
c, d := swap(a, b)
fmt.Println(c, d)
}
Результат:
[simterm]
$ go run mult.go one two
two one
[/simterm]
Аргументы функции
Когда функция использует аргументы — в её заголовке должны быть указаны типы переменных, которые будут принимать эти аргументы. Такие переменные называются формальные параметрами (formal parameter) функции.
Формальные параметры ведут себя в функции как обычные локальные фукнции переменные, создаются при начале выполнения функции и удаляются при её завершении.
При вызове функции имеется два способа передачи аргументов:
| Sr.No | Call Type & Description |
|---|---|
| 1 | Call by value
Вызов по значению — этот способ выполняет копирование непосредственно значения аргумента в формальный параметр функции, т.е. значение запсиывается в участок памяти, выделенный под переменную, которая является формальным аргументом функции. В таком случае изменения, сделанные внутри функции, не повлияют на значение аргумента. |
| 2 | Call by reference
Вызов по ссылке — этот методе копирует адрес участка памяти, который содержит значение аргумента в формальный параметр. Внутри функции этот адрес используется для обработки и изменения значения.
|
Вызов по значению
По умолчанию в Go используется этот метод передачи данных в функцию, что означает, что функция не может менять значение аругмента.
Например, функция swap():
/* function definition to swap the values */
func swap(int x, int y) int {
var temp int
temp = x /* save the value of x */
x = y /* put y into x */
y = temp /* put temp into y */
return temp;
}
Теперь — вызовем её, и передадим ей значения из main():
package main
import "fmt"
func main() {
// local variable definition
var a int = 100
var b int = 200
fmt.Printf("Before swap, value of a : %d\n", a )
fmt.Printf("Before swap, value of b : %d\n", b )
// calling a function to swap the values
swap(a, b)
fmt.Printf("After swap, value of a : %d\n", a )
fmt.Printf("After swap, value of b : %d\n", b )
}
func swap(x, y int) int {
var temp int
temp = x // save the value of x
x = y // put y into x
y = temp // put temp into y
return temp;
}
И результат выполнения:
[simterm]
$ go run swap.go
Before swap, value of a : 100
Before swap, value of b : 200
After swap, value of a : 100
After swap, value of b : 200
[/simterm]
Мы видим, что хотя внутри функции swap() значения были поменяны местами — их реальные значения вне функции остались неизменными.
Вызов по ссылке
Примечание: указатели ещё не рассматривались, можно посмотреть в посте C: указатели – подробный разбор
Для передачи значения по ссылке — функции передаётся указатель аргумента. Соответсвенно, при описании функции в её заголовке вы должны указать тип переменных параметров как указатель.
Например:
/* function definition to swap the values */
func swap(x *int, y *int) {
var temp int
temp = *x /* save the value at address x */
*x = *y /* put y into x */
*y = temp /* put temp into y */
}
Теперь давайте вызовем swap(), передав значения по указателю:
package main
import "fmt"
func main() {
// local variable definition
var a int = 100
var b int = 200
fmt.Printf("Before swap, value of a : %d\n", a )
fmt.Printf("Before swap, value of b : %d\n", b )
/* calling a function to swap the values.
* &a indicates pointer to a ie. address of variable a and
* &b indicates pointer to b ie. address of variable b.
*/
swap(&a, &b)
fmt.Printf("After swap, value of a : %d\n", a )
fmt.Printf("After swap, value of b : %d\n", b )
}
func swap(x *int, y *int) {
var temp int
temp = *x // save the value at address x
*x = *y // put y into x
*y = temp // put temp into y
}
И результат:
[simterm]
$ go run swap_rf.go
Before swap, value of a : 100
Before swap, value of b : 200
After swap, value of a : 200
After swap, value of b : 100
[/simterm]
Теперь видно, что изменения в функции затронули и значения вне её, в отличии от использования вызова по значению.
Применение функций
Функции можно применять следующими способами:
| Sr.No | Function Usage & Description |
|---|---|
| 1 | Function as ValueФункция создаётся «на лету», и используется как значение. |
| 2 | Function ClosuresЗамыкания — анонимные функции в динамическом программировании |
| 3 | MethodМетоды — специальные функции с получателями (receiver) |
Функция как значение
В Go предоставляется возможность создавать функции на лету и использовать их как значения.
В следующем примере мы инициализируем переменную с описанием функции, чья роль — просто использовать встроенную функцию math.sqrt():
package main
import (
"fmt"
"math"
)
func main(){
// declare a function variable
getSquareRoot := func(x float64) float64 {
return math.Sqrt(x)
}
// use the function
fmt.Println(getSquareRoot(9))
}
Результат:
[simterm]
$ go run func_val.go
3
[/simterm]
Замыкания
В Go поддерживаются анонимные функции, которые работают как функции замыкания. Анонимные функции используются когда мы хотим создать функцию без объявления её имени.
В следующем примере мы создадим функцию getSequence(), которая возвращает другую функцию. Роль этой функции — использовать внешнюю ей переменную i вышестоящей функции, что бы сформировать замыкание:
package main
import "fmt"
func getSequence() func() int {
i:=0
return func() int {
i+=1
return i
}
}
func main(){
// nextNumber is now a function with i as 0
nextNumber := getSequence()
// invoke nextNumber to increase i by 1 and return the same
fmt.Println(nextNumber())
fmt.Println(nextNumber())
fmt.Println(nextNumber())
// create a new sequence and see the result, i is 0 again
nextNumber1 := getSequence()
fmt.Println(nextNumber1())
fmt.Println(nextNumber1())
}
Результат:
[simterm]
$ go run func_clos.go
1
2
3
1
2
[/simterm]
Методы
Go поддерживает специальные типы функций, называемые методами. В объявлении методов присутсвует «получатель», который представляет собой контейнер функции. Этот получатель может быть использован, что бы вызывать функцию используя оператор «.«.
Синтаксис:
func (variable_name variable_data_type) function_name() [return_type]{
/* function body*/
}
Пример:
package main
import (
"fmt"
"math"
)
// define a circle
type Circle struct {
x,y,radius float64
}
// define a method for circle
func(circle Circle) area() float64 {
return math.Pi * circle.radius * circle.radius
}
func main(){
circle := Circle{x:0, y:0, radius:5}
fmt.Printf("Circle area: %f\n", circle.area())
}
[simterm]
$ go run func_meth.go
Circle area: 78.539816
[/simterm]
Продолжение.
7 310 views