Функция как значение. Тип функции


Каждая функция имеет определенный тип, который складывается из типов параметров функции и типа возвращаемого значения.

Например, пусть у нас есть следующая функция:

1
2
3
4
func sum(_ x: Int, _ y: Int) -> Int{

return x + y
}
Эта функция имеет тип (Int, Int) -> Int

Или, например, функция:

1
2
3
4
func printName(name: String){

print(name)
}
Она имеет тип (String) -> Void

Используя тип функции, мы можем определять переменные или константы этого типа и затем динамически назначать их конкретные функции:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
func sum(_ a: Int, _ b: Int) -> Int{

return a + b
}

func subtract(_ a: Int, _ b: Int) -> Int{

return a - b
}

var someFunc: (Int, Int) -> Int

someFunc = sum

print(someFunc(5, 4)) // 9

someFunc = subtract

print(someFunc(5, 4)) // 1
Итак, здесь у нам определены две функции sum и subtract, которые имеют одни и те же параметры и возвращаемые типы значений, но отличаются конкретными действиями: в одном случае идет сложение, а в другом - вычитание чисел.

Также определена переменная someFunc, которая имеет тип - функцию с двумя параметрами типа Int и возвращаемым значением типа Int. То есть переменная someFunc по параметрам и возвращаемому типу соответствует функциям sum и subtract. Поэтому мы можем динамически приравнять переменную одной из функций и вызвать ее:

1
2
someFunc = sum
print(someFunc(5, 4)) // 9
Фактически здесь будет вызываться функция sum. Поэтому в качестве результата мы получим сумму 4 + 5.

Затем динамически мы можем приравнять переменную другой функции:

1
2
someFunc = subtract
var result = someFunc(5, 4) // 1
Подобная функциональность открывает нам большие возможности. В частности, мы можем использовать типы функций в качестве типов параметров или в качестве возвращаемых типов в других функциях.

Типы функций в качестве типов параметров
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
func sum(_ a: Int, _ b: Int) -> Int{

return a + b
}

func subtract(_ a: Int, _ b: Int) -> Int{

return a - b
}

func getResult(_ binaryFunc: (Int, Int) -> Int, _ a: Int, _ b: Int){

let result = binaryFunc(a, b)
print(result)
}

getResult(sum, 13, 10) // 23

getResult(subtract, 12, 8) // 4
Здесь функция getResult в качестве первого параметра принимает функцию. Типу этого параметры соответствуют выше определенные функции sum и substract, поэтому они могут использоваться при вызове функции getResult:

1
getResult(sum, 13, 10)
Типы функций как типы возвращаемых значений
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
func add(_ x: Int, _ y: Int) -> Int {return x + y}
func subtract(_ x: Int, _ y: Int) -> Int {return x - y}
func multiply(_ x: Int, _ y: Int) -> Int {return x * y}

func select (_ n: Int) -> (Int, Int) -> Int{

switch n {
case 2:
return subtract
case 3:
return multiply
default:
return add
}
}

let x = 12, y = 8

var someFunc = select(1) // add
print(someFunc(x, y)) // 20

someFunc = select(2) // subtract
print(someFunc(x, y)) // 4

someFunc = select(3) // multiply
print(someFunc(x, y)) // 96
Возвращаемым типом функции select является тип (Int, Int) -> Int. Это значит, что select должна возвратить функцию, которая принимает два параметра типа Int и возвращает значение типа Int. Под это определение подходят функции sum, multiply и subtract. Поэтому в select мы возвращаем не конкретное значение, а одну из этих функций в зависимости от значения параметра n.

Возвращаемый результат мы можем присвоить переменной или константе:

1
var someFunc = select(1) // add
И затем через эту переменную можно будет обращаться к возвращенной функции.